Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
faf84c0
docs: session notes catch-up + add M-sec CI design doc
devonartis Apr 10, 2026
7cfe3f1
plan: add M-sec CI/build/gates v1 implementation plan + FLOW update
devonartis Apr 10, 2026
82ae620
docs(flow): slim M-sec entry to decision + action + next only
devonartis Apr 10, 2026
65bf04b
chore(gates): add gosec config for M-sec pipeline
devonartis Apr 10, 2026
5634256
style: gofmt -w across repo (no logic changes)
devonartis Apr 10, 2026
70a62a0
fix(keystore): check ed25519 public-key type assertion
devonartis Apr 10, 2026
a172693
fix(mutauth): log heartbeat auto-revoke failures instead of dropping
devonartis Apr 10, 2026
ab51db0
fix(aactl): propagate errors from json.Marshal and io.ReadAll in client
devonartis Apr 10, 2026
0c0b275
docs(store): justify gosec G202 suppression on audit query SELECT
devonartis Apr 10, 2026
951670a
docs(admin/test): clarify TestLaunchTokenRecord_SpecCompliance intent
devonartis Apr 10, 2026
610fa28
chore(gates): add golangci-lint M-sec config
devonartis Apr 10, 2026
53d91fe
docs(techdebt): record TD-VUL-001..004 govulncheck baseline (stdlib)
devonartis Apr 10, 2026
65160b9
chore(gates): extend gates.sh with M-sec gate set
devonartis Apr 10, 2026
94d8f6c
feat(gates): add L2.5 core contract smoke script
devonartis Apr 10, 2026
dd7be48
chore(gates): add gate-parity enforcement script
devonartis Apr 10, 2026
512cbfc
chore(gates): use 'syft scan' (replaces deprecated 'syft packages')
devonartis Apr 10, 2026
5637a38
docs(changelog): add M-sec CI/build/gates v1 entry
devonartis Apr 10, 2026
a95e1b0
chore(deps): add Dependabot config for github-actions, gomod, docker
devonartis Apr 10, 2026
6af9a77
chore(github): add CODEOWNERS and MAINTAINERS allowlist
devonartis Apr 10, 2026
db6db15
feat(ci): add main CI workflow with 13 parallel gates
devonartis Apr 10, 2026
c671c93
feat(ci): add CodeQL SAST workflow
devonartis Apr 10, 2026
b2e42f9
feat(ci): add OpenSSF Scorecard workflow
devonartis Apr 10, 2026
ea6130b
feat(ci): add nightly L4 full regression workflow
devonartis Apr 10, 2026
2225b37
feat(ci): add contribution policy enforcement workflow
devonartis Apr 10, 2026
04e1330
fix(ci): rename smoke-l2.5 → smoke-l25 (invalid job ID)
devonartis Apr 10, 2026
e786214
chore(gitignore): ignore gate artifacts (coverage.out, sbom.spdx.json)
devonartis Apr 10, 2026
5a97a14
chore(ci): pin all action SHAs for supply chain safety
devonartis Apr 10, 2026
b5ac1b5
chore(deps): bump Go toolchain go1.25.7 → go1.25.9
devonartis Apr 10, 2026
fb60292
fix(ci): pin golangci-lint-action back to v6 + remove dep-review
devonartis Apr 10, 2026
ecae772
fix(ci): pin golangci-lint version to v1.64.8
devonartis Apr 10, 2026
7c73b3a
fix(ci): disable CodeQL + Scorecard until public flip (GHAS)
devonartis Apr 10, 2026
72f96d3
fix(ci): install golangci-lint from source instead of pre-built action
devonartis Apr 10, 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
5 changes: 5 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Global ownership — all paths default to the maintainer.
# Per Decision 014, external contributions are not accepted, so CODEOWNERS
# primarily serves as documentation and branch-protection review enforcement.

* @devonartis
11 changes: 11 additions & 0 deletions .github/MAINTAINERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# MAINTAINERS — allowlist for contribution-policy.yml
#
# Users listed here bypass the auto-close policy in
# .github/workflows/contribution-policy.yml. Anyone else opening a PR
# (except dependabot and github-actions bot) gets auto-closed with a
# templated comment pointing to the issues-only contribution policy
# (Decision 014).
#
# Format: one GitHub username per line, no @ prefix, no inline comments.

devonartis
69 changes: 69 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Dependabot config for agentauth-core
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
#
# Why each ecosystem is here:
# - github-actions: SHA pinning (Task 22) means Dependabot is the only
# thing that rotates actions. Without this block, pinned SHAs stale.
# - gomod: direct and indirect Go module updates. Groups by dependency
# type so 'chore(deps): bump direct deps' PRs are reviewable as a unit.
# - docker: Dockerfile base image updates. Separate limit because these
# PRs often touch runtime behavior and deserve individual review.

version: 2
updates:
# GitHub Actions — SHA maintenance for pinned workflow steps
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "06:00"
timezone: "UTC"
open-pull-requests-limit: 3
commit-message:
prefix: "chore(deps)"
include: "scope"
groups:
github-actions:
patterns:
- "*"
labels:
- "dependencies"
- "github-actions"

# Go modules — direct and indirect dependencies
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "06:00"
timezone: "UTC"
open-pull-requests-limit: 3
commit-message:
prefix: "chore(deps)"
include: "scope"
groups:
go-direct:
dependency-type: "direct"
go-indirect:
dependency-type: "indirect"
labels:
- "dependencies"
- "go"

# Docker base images
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "06:00"
timezone: "UTC"
open-pull-requests-limit: 2
commit-message:
prefix: "chore(deps)"
include: "scope"
labels:
- "dependencies"
- "docker"
296 changes: 296 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
name: CI

# GATE_LIST_START
# - build
# - vet
# - lint
# - format
# - contamination
# - unit-tests
# - gosec
# - govulncheck
# - go-mod-verify
# - unit-tests-race
# - docker-build
# - smoke-l25
# - sbom
# GATE_LIST_END

on:
pull_request:
branches: [develop]
push:
branches: [develop, main]

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

# Parameterized — no hardcoded owner/repo names. Rebrand-resilient per Decision 015.
permissions:
contents: read

jobs:
build:
name: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
cache: true
- run: go build ./cmd/broker ./cmd/aactl

vet:
name: vet
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
cache: true
- run: go vet ./...

lint:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
cache: true
# DO NOT use golangci/golangci-lint-action here. Its pre-built
# binaries are compiled against an older Go toolchain (≤ 1.23)
# and exit 3 on our code because the go.mod toolchain directive
# is 1.25.9 — the embedded linter can't parse 1.25 stdlib/SSA.
#
# Instead, `go install` golangci-lint from source. This compiles
# it with the CI runner's Go (matching our toolchain.go1.25.9)
# so it parses the same way as local developers' brew-installed
# binary. Migration to golangci-lint v2 (which fixes this) is
# tracked for a later cycle.
- name: Install golangci-lint
run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.8
- name: Run lint
run: golangci-lint run --config .golangci.yml ./...

format:
name: format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
- run: |
unformatted=$(gofmt -l .)
if [[ -n "$unformatted" ]]; then
echo "The following files are not gofmt'd:"
echo "$unformatted"
exit 1
fi

contamination:
name: contamination
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- run: |
if grep -ri 'hitl\|approval\|oidc\|federation\|cloud\|sidecar' internal/ cmd/ 2>/dev/null; then
echo "FAIL: enterprise references found in core code"
exit 1
fi
echo "PASS: no enterprise contamination"

unit-tests:
name: unit-tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
cache: true
- run: go test -short -count=1 ./...

unit-tests-race:
name: unit-tests-race
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
cache: true
- run: go test -race -count=1 -coverprofile=coverage.out ./...
- uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
with:
files: ./coverage.out
fail_ci_if_error: false
verbose: true

gosec:
name: gosec
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
# Exclusions (G117, G304, G101) are documented in .gosec.yml and
# mirrored in scripts/gates.sh and .golangci.yml.
- uses: securego/gosec@223e19b8856e00f02cc67804499a83f77e208f3c # v2.25.0
with:
args: '-quiet -conf .gosec.yml -exclude=G117,G304,G101 -severity=medium ./...'

govulncheck:
name: govulncheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
- run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...

go-mod-verify:
name: go-mod-verify
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
- run: |
go mod verify
go mod tidy
if ! git diff --exit-code go.mod go.sum; then
echo "FAIL: go.mod or go.sum changed after 'go mod tidy'"
exit 1
fi

docker-build:
name: docker-build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Build image
run: docker build -t agentauth-ci:${{ github.sha }} .

smoke-l25:
name: smoke-l25
runs-on: ubuntu-latest
needs: [docker-build]
env:
AA_ADMIN_SECRET: live-test-secret-32bytes-long-ok # known test fixture
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install python cryptography (for Ed25519 challenge-response)
run: python3 -m pip install --user cryptography
- name: Start broker
run: |
export AA_ADMIN_SECRET="$AA_ADMIN_SECRET"
./scripts/stack_up.sh
for i in {1..30}; do
if curl -sf http://localhost:8080/v1/health >/dev/null 2>&1; then
echo "Broker up after $i seconds"
break
fi
sleep 1
done
- name: Run L2.5 core contract smoke
run: ./scripts/smoke/core-contract.sh
- name: Teardown
if: always()
run: ./scripts/stack_down.sh || true

sbom:
name: sbom
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
with:
path: .
format: spdx-json
output-file: sbom.spdx.json
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: sbom
path: sbom.spdx.json
retention-days: 30

# dep-review is removed temporarily: actions/dependency-review-action
# requires GitHub Advanced Security (GHAS) on private repos. devonartis/
# agentauth is private without GHAS, so the action fails with a 403
# from the Dependency Graph API on every PR. Re-enable when:
# (a) the repo flips public (GHAS is free on public repos), OR
# (b) GHAS is purchased for the private repo.
# Tracking: TD-VUL-005 in TECH-DEBT.md.

changelog:
name: changelog
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Check CHANGELOG.md diff
run: |
if echo '${{ toJson(github.event.pull_request.labels) }}' | grep -q '"skip-changelog"'; then
echo "Label 'skip-changelog' present — bypassing CHANGELOG check"
exit 0
fi
BASE_SHA='${{ github.event.pull_request.base.sha }}'
if git diff --name-only "$BASE_SHA" HEAD | grep -q '^CHANGELOG.md$'; then
echo "PASS: CHANGELOG.md touched in this PR"
else
echo "FAIL: This PR does not touch CHANGELOG.md"
echo "Add a CHANGELOG entry or apply the 'skip-changelog' label if the PR is docs/tests-only."
exit 1
fi

gate-parity:
name: gate-parity
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- run: ./scripts/test-gate-parity.sh

gates-passed:
name: gates-passed
runs-on: ubuntu-latest
needs:
- build
- vet
- lint
- format
- contamination
- unit-tests
- unit-tests-race
- gosec
- govulncheck
- go-mod-verify
- docker-build
- smoke-l25
- sbom
- gate-parity
if: always()
steps:
- name: Check all gates passed
run: |
if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then
echo "One or more gates failed"
exit 1
fi
if [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then
echo "One or more gates were cancelled"
exit 1
fi
echo "All gates passed"
Loading