diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6b52b2c..cbe6cdb 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -7,17 +7,51 @@ on: permissions: contents: read - id-token: write env: HYPHEN_PUBLIC_API_KEY: ${{ secrets.HYPHEN_PUBLIC_API_KEY }} HYPHEN_APPLICATION_ID: ${{ secrets.HYPHEN_APPLICATION_ID }} jobs: - build: - + scan-release: runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Install Socket Firewall + uses: SocketDev/action@ba6de6cc0565af1f42295590380973573297e31f # v1.3.2 + with: + mode: firewall-free + firewall-version: "1.15.1" + + - name: Set up Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 24 + package-manager-cache: false + - name: Install Aikido CI client + # zizmor: ignore[adhoc-packages] pinned Aikido CI client for the release gate + run: sfw npm install --global @aikidosec/ci-api-client@1.0.17 + + # Fails on new SAST/IaC/secrets findings. The API key comes from Aikido's + # Continuous Integration settings — it grants no publish authority. + - name: Run Aikido release scan + env: + REPO_NAME: ${{ github.event.repository.name }} + AIKIDO_CLIENT_API_KEY: ${{ secrets.AIKIDO_CLIENT_API_KEY }} + run: > + aikido-api-client scan-release + "$REPO_NAME" "$GITHUB_SHA" + --apikey "$AIKIDO_CLIENT_API_KEY" + --fail-on-sast-scan --fail-on-iac-scan --fail-on-secrets-scan + + build: + needs: [scan-release] + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: diff --git a/DEFENSE_IN_DEPTH.md b/DEFENSE_IN_DEPTH.md index 171a1e9..928a6cd 100644 --- a/DEFENSE_IN_DEPTH.md +++ b/DEFENSE_IN_DEPTH.md @@ -36,7 +36,7 @@ Profile: npm library · public ## 5. npm publishing — npm libraries only - [ ] OIDC trusted publishing configured **stage-only** on npmjs.com for the publish workflow — it can stage, never publish live (manual) -- [ ] `.github/workflows/release.yaml` packs then stages with `pnpm stage publish ./packed/*.tgz --no-git-checks` (PR #74 pending) +- [x] `.github/workflows/release.yaml` packs then stages with `pnpm stage publish ./packed/*.tgz --no-git-checks` — PR #74 - [ ] Maintainer promotes staged versions with 2FA (manual) - [ ] Drydock connected — staged releases reviewed before promotion (manual) - [ ] No direct publish rights: package requires 2FA and disallows tokens (manual) @@ -44,7 +44,7 @@ Profile: npm library · public ## 6. Security tooling - [x] Aikido runs on every build — verified 2026-09-09 (PR #65: Aikido Security: check code) -- [ ] Aikido release gate: the release workflow's stage-publish job `needs:` a passing `scan-release` +- [ ] Aikido release gate: the release workflow's stage-publish job `needs:` a passing `scan-release` (PR #75 pending) - [ ] Socket reviews every PR that changes dependencies ## 7. Repository lockdown diff --git a/SECURITY.md b/SECURITY.md index 17e0f35..20598f4 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -27,7 +27,7 @@ hardening checklist; progress is tracked in [DEFENSE_IN_DEPTH.md](./DEFENSE_IN_D - Dependencies install through pnpm with a 7-day cooldown on new versions, lifecycle scripts blocked by default, `trustPolicy: no-downgrade`, and exotic subdependencies blocked. - The lockfile is committed and CI installs with `--frozen-lockfile`. There is no Dependabot config; dependency updates go through reviewed PRs. - CI workflows default to read-only `contents: read` permissions; generated output is never committed back from CI; every action is pinned to a full commit SHA; Socket Firewall (`sfw`) wraps `pnpm install`; zizmor lints workflows on every PR; checkouts that do not push set `persist-credentials: false`. -- The release workflow disables `setup-node` package-manager caching. +- The release workflow disables `setup-node` package-manager caching and stages packed tarballs with `pnpm stage publish` instead of publishing live. - Workflows do not use `pull_request_target`. - The published package sets `repository.url` to this repo so provenance can map back. - `.github/CODEOWNERS` names `@jaredwray` for `/.github/`, `/.vscode/`, `/.cursor/`, `/.devcontainer/`, and `/scripts/`.