Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
1e32e7a
feat(release): Helm chart distribution to Artifact Hub and multi-arch…
Sanjaykumar-2005 May 16, 2026
b8402a8
feat(github): welcome first-time commenters with /assign nudge and st…
btwshivam May 16, 2026
eb7ed7f
feat(github): GSSoC auto-labels for difficulty and mentor attribution
btwshivam May 16, 2026
161c902
fix(github): grant issues:write to GSSoC label workflows
btwshivam May 16, 2026
bdfe9a6
feat(cli): add --no-banner flag to suppress ASCII header (#71)
shine-sri May 16, 2026
7a08799
feat: implement Helm chart packaging and automated release workflow v…
Sanjaykumar-2005 May 17, 2026
88b00cd
feat(cli): add shell completion for bash, zsh, fish, powershell (#55)
Kshitij-K-Singh May 23, 2026
c66b7b3
feat(cli): add no-color support for CLI output (#57)
Vidheendu May 23, 2026
bffb27a
feat(cli): add man page generation via make manpage (#73)
Kshitij-K-Singh May 23, 2026
27025a5
build(deps): bump actions/github-script from 7 to 9 in the actions gr…
dependabot[bot] May 23, 2026
57efe1f
feat: add initial Helm chart for Kerno and configure Artifact Hub met…
Sanjaykumar-2005 May 24, 2026
ebbdff8
feat(release): Helm chart distribution to Artifact Hub and multi-arch…
Sanjaykumar-2005 May 16, 2026
b9662e5
feat: implement Helm chart packaging and automated release workflow v…
Sanjaykumar-2005 May 17, 2026
ca08b99
feat: add initial Helm chart for Kerno and configure Artifact Hub met…
Sanjaykumar-2005 May 24, 2026
5501b86
Merge branch 'feat/distribution-multi-arch' of https://github.com/San…
Sanjaykumar-2005 May 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ jobs:
steps:
- uses: actions/checkout@v6

- name: Set up QEMU
uses: docker/setup-qemu-action@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4

Expand All @@ -160,6 +163,7 @@ jobs:
with:
context: .
push: false
platforms: linux/amd64,linux/arm64
tags: ghcr.io/optiqor/kerno:ci
cache-from: type=gha
cache-to: type=gha,mode=max
2 changes: 1 addition & 1 deletion .github/workflows/enforce-issue-cap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Find over-cap contributors and trim
uses: actions/github-script@v7
uses: actions/github-script@v9
with:
script: |
const repo = { owner: context.repo.owner, repo: context.repo.repo };
Expand Down
141 changes: 141 additions & 0 deletions .github/workflows/gssoc-difficulty.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Copyright 2026 Optiqor contributors
# SPDX-License-Identifier: Apache-2.0
#
# Auto-applies a level:* difficulty label to every PR. One label per PR.
# Re-runs on synchronize, so a PR that grows out of its initial bucket
# gets re-classified on each push.
#
# Classification (strict; checked top-to-bottom, first match wins):
#
# level:critical — touches BPF C, AI, daemon entry, release tooling,
# install script, Dockerfile, security workflows,
# or K8s RBAC / security context. Size-independent.
#
# level:beginner — ONLY trivial paths (docs, templates, fixtures,
# .gitignore) AND ≤ 5 files. Any size in that scope.
# A README rewrite is beginner. A typo is beginner.
#
# level:advanced — 400+ total lines OR 9+ files; OR a code path
# (internal/, pkg/, cmd/) with 100+ lines or 5+ files.
#
# level:intermediate — everything else. Default bucket for code work
# under 100 lines, and for non-code config tweaks
# that aren't trivial docs.
#
# If you need to override, comment with /level <bucket> — not wired yet
# but the override path is reserved.

name: GSSoC difficulty label

on:
pull_request_target:
types: [opened, synchronize, reopened]

permissions:
contents: read
issues: write # /issues/:n/labels endpoint is under the issues resource
pull-requests: write

jobs:
classify:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v9
with:
script: |
const repo = { owner: context.repo.owner, repo: context.repo.repo };
const pr = context.payload.pull_request;
const prNumber = pr.number;

const files = await github.paginate(github.rest.pulls.listFiles, {
...repo, pull_number: prNumber, per_page: 100,
});
const paths = files.map(f => f.filename);

// ── Critical surface (size-independent) ────────────────────
//
// A bug here can cause kernel-verifier rejection, capability
// widening, secret leakage, or a bad release artifact.
const criticalPatterns = [
/^internal\/bpf\/c\//, // BPF C source — verifier risk
/^internal\/bpf\/.*loader\.go$/, // BPF program loaders
/^internal\/ai\//, // privacy + API key handling
/^internal\/cli\/start\.go$/, // daemon entry + capabilities
/^Dockerfile/, // production image
/^scripts\/install\.sh$/, // root install + supply chain
/^SECURITY\.md$/,
/^\.goreleaser/,
/^\.github\/workflows\/(release|codeql|cosign|security)/,
/^deploy\/.*(rbac|security[Cc]ontext|securitycontext)/,
];

// ── Code paths (intermediate floor) ────────────────────────
//
// Any non-trivial change in these paths is at least intermediate.
// Touching the doctor engine, a collector, or a CLI command
// requires understanding the codebase — not beginner work.
const codePathPatterns = [
/^internal\//,
/^pkg\//,
/^cmd\//,
];

// ── Trivial paths (beginner ceiling) ────────────────────────
//
// PRs that touch ONLY these paths qualify for beginner regardless
// of line count. Docs, config, fixtures, issue/PR templates.
const trivialPatterns = [
/\.md$/,
/\.gitignore$/,
/\.editorconfig$/,
/^docs\//,
/^testdata\//,
/^demo\./,
/^\.github\/ISSUE_TEMPLATE\//,
/^\.github\/PULL_REQUEST_TEMPLATE\.md$/,
/^\.github\/mlc-config\.json$/,
/^\.github\/labeler\.yml$/,
/^\.github\/dependabot\.yml$/,
/^LICENSE$/,
/^CODE_OF_CONDUCT\.md$/,
/^GOVERNANCE\.md$/,
];

const lines = (pr.additions || 0) + (pr.deletions || 0);
const fileCount = paths.length;
const touchesCritical = paths.some(p => criticalPatterns.some(re => re.test(p)));
const touchesCode = paths.some(p => codePathPatterns.some(re => re.test(p)));
const allTrivial = paths.length > 0 && paths.every(p => trivialPatterns.some(re => re.test(p)));

let level;
if (touchesCritical) {
level = 'level:critical';
} else if (allTrivial && fileCount <= 5) {
level = 'level:beginner';
} else if (lines >= 400 || fileCount >= 9) {
level = 'level:advanced';
} else if (touchesCode && (lines >= 100 || fileCount >= 5)) {
level = 'level:advanced';
} else if (touchesCode) {
level = 'level:intermediate';
} else {
level = 'level:intermediate';
}

core.info(
`PR #${prNumber}: ${lines} lines, ${fileCount} files, ` +
`critical=${touchesCritical}, code=${touchesCode}, allTrivial=${allTrivial} → ${level}`
);

// Strip any other level:* label, then apply the chosen one.
const currentLabels = (pr.labels || []).map(l => l.name);
for (const old of currentLabels) {
if (old.startsWith('level:') && old !== level) {
await github.rest.issues.removeLabel({
...repo, issue_number: prNumber, name: old,
}).catch(() => {});
}
}
await github.rest.issues.addLabels({
...repo, issue_number: prNumber, labels: [level],
});
66 changes: 66 additions & 0 deletions .github/workflows/gssoc-mentor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Copyright 2026 Optiqor contributors
# SPDX-License-Identifier: Apache-2.0
#
# When a maintainer (repo collaborator with write+) submits an APPROVED
# review, apply `mentor:<their-username>` to the PR. The scoring engine
# uses this label to credit the reviewing mentor with points.
#
# Multiple maintainers approving = multiple mentor:* labels. That is
# intentional: every reviewer who signed off gets credit.

name: GSSoC mentor attribution

on:
pull_request_review:
types: [submitted]

permissions:
contents: read
issues: write # /repos/:o/:r/labels and /issues/:n/labels live under the issues resource
pull-requests: write

jobs:
attribute:
if: github.event.review.state == 'approved'
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v9
with:
script: |
const repo = { owner: context.repo.owner, repo: context.repo.repo };
const reviewer = context.payload.review.user.login;
const prNumber = context.payload.pull_request.number;

// Only collaborators with write+ count as mentors.
let isMaintainer = false;
try {
const perm = await github.rest.repos.getCollaboratorPermissionLevel({
...repo, username: reviewer,
});
const lvl = perm.data.permission;
isMaintainer = (lvl === 'admin' || lvl === 'write' || lvl === 'maintain');
} catch (e) {
core.info(`@${reviewer} not a collaborator; skipping mentor attribution`);
return;
}
if (!isMaintainer) {
core.info(`@${reviewer} lacks write+; skipping`);
return;
}

const label = `mentor:${reviewer}`;

// Create the label on the fly so we don't need to pre-register
// every maintainer's username. Pastel gray so they don't shout.
await github.rest.issues.createLabel({
...repo,
name: label,
color: 'C5C5C5',
description: `Reviewed and approved by @${reviewer}`,
}).catch(() => {}); // label may already exist

await github.rest.issues.addLabels({
...repo, issue_number: prNumber, labels: [label],
});

core.info(`applied ${label} to PR #${prNumber}`);
48 changes: 48 additions & 0 deletions .github/workflows/helm-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright 2026 Optiqor contributors
# SPDX-License-Identifier: Apache-2.0

name: Helm Chart Release

on:
push:
tags:
- "v*"

permissions:
contents: write

jobs:
release-chart:
name: Release Chart
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"

- name: Install Helm
uses: azure/setup-helm@v4

- name: Run chart-releaser
uses: helm/chart-releaser-action@v1
with:
charts_dir: deploy/helm
env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

# After chart-releaser finishes, it has updated gh-pages.
# We need to ensure artifacthub-repo.yml is in the root of gh-pages.
- name: Push Artifact Hub metadata
run: |
cp artifacthub-repo.yml /tmp/ahr.yml
git checkout gh-pages

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git checkout gh-pages here is fragile. chart-releaser-action pushes gh-pages over the api and doesn't leave a local gh-pages branch, so after a fresh checkout@v6 this either fails with pathspec gh-pages did not match or races chart-releaser's own push and hits a non-fast-forward. the job only runs on tag, so ci never exercised it. simpler: commit artifacthub-repo.yml to the gh-pages root once by hand, or use chart-releaser's own index/pages options instead of a manual checkout+push.

cp /tmp/ahr.yml ./artifacthub-repo.yml
git add artifacthub-repo.yml
git commit -m "chore: update artifacthub-repo.yml" || echo "No changes to commit"
git push origin gh-pages
2 changes: 1 addition & 1 deletion .github/workflows/pr-commands.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Parse and dispatch
uses: actions/github-script@v7
uses: actions/github-script@v9
with:
script: |
const body = context.payload.comment.body || '';
Expand Down
52 changes: 52 additions & 0 deletions .github/workflows/welcome-commenter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Copyright 2026 Optiqor contributors
# SPDX-License-Identifier: Apache-2.0
#
# Welcomes a contributor on their first issue comment. Sister to
# welcome.yml, which only fires on issue/PR open.

name: Welcome first-time commenters

on:
issue_comment:
types: [created]

permissions:
issues: write

jobs:
welcome:
if: |
github.event.comment.user.type != 'Bot' &&
github.event.comment.user.login != github.repository_owner &&
github.event.comment.user.login != github.event.issue.user.login &&
!github.event.issue.pull_request
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v9
with:
script: |
const repo = { owner: context.repo.owner, repo: context.repo.repo };
const commenter = context.payload.comment.user.login;
const issueNumber = context.payload.issue.number;

// Skip if the user has already commented on a different issue.
const res = await github.rest.search.issuesAndPullRequests({
q: `repo:${repo.owner}/${repo.repo} commenter:${commenter} is:issue`,
per_page: 10,
});
if ((res.data.items || []).some(i => i.number !== issueNumber)) {
core.info(`@${commenter} is not a first-time commenter; skipping`);
return;
}

const body =
`Hey @${commenter}, welcome. Looks like this is your first comment in the repo.\n\n` +
`Want to work on this issue? Reply with \`/assign\` or \`/take\` to claim it.\n\n` +
`If the work's been useful, two quick ways to help:\n\n` +
`⭐ [Star kerno](https://github.com/optiqor/kerno): eBPF kernel diagnosis engine\n` +
`⭐ [Star optiqor-cli](https://github.com/optiqor/optiqor-cli): Kubernetes cost remediation that lives in the pull request\n\n` +
`Thanks for showing up.`;

await github.rest.issues.createComment({
...repo, issue_number: issueNumber, body,
});
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ Thumbs.db
# Debug
__debug_bin*

# Man pages (generatable via make manpage)
docs/man/*.1

# Environment
.env
.env.local
Expand Down
9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ UI_DIST_DIR := internal/dashboard/dist/assets
.PHONY: all build build-ebpf build-debug test test-cover test-race lint vet check \
fmt clean bpf generate docker help \
ui-fetch ui-dev install-tools setup precommit \
verify demo demo-cast bpf-verify
verify demo demo-cast bpf-verify manpage

.DEFAULT_GOAL := help

Expand Down Expand Up @@ -167,6 +167,13 @@ docker:
--build-arg DATE=$(DATE) \
.

# ─── Man Pages ────────────────────────────────────────────────────────────────

## manpage: Generate man pages for all CLI commands
manpage:
@mkdir -p docs/man
go run ./cmd/kerno-mangen/

# ─── Utilities ───────────────────────────────────────────────────────────────

## install-tools: Install Go-based development tools (golangci-lint, bpf2go)
Expand Down
Loading