Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 3 additions & 6 deletions .auths/allowed_signers
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
# auths:managed — do not edit manually
# Current identity (E6IXlw5-lnX88r3WZCt3u1qyN_Xlq7nQjtoTmuOfMIjI)
z6MktnihicwetvA16FtHFynaJTn9eDZw51eizUEA1yGJCR4o@auths.local namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINT/yz5N7+GkzsRTHiyaueZbDy+fovwYUXyJ9uwD67tk
# Previous identities
z6MkipUqayiDZWM8j4YktjiEFZcCGw51YDVvLM7SrYPqLLyZ@auths.local namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEDeaOmUEcUjzChUedAsPyDO4mnjIa8j92fD9rGpuZd0
z6MkhfnUUc2UJJ5C9sQQ7GvXmSbQJsdtNKV6HNYcQtTjc7xE@auths.local namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC/Ib83sxXogDnEVzLjFBkyC+DhP+cssbPzZAmQhB+Lz
z6Mkio7WpoPy5EfeMJwhiZzePFch7xxuDeF9tpAf9q15nnHf@auths.local namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIECEt+3NgK9ws6M65lPSqW1FgWFjCYQVj1fsDedIvkRi
# auths:attestation
z6MkhPJCPXd5A9VN4wScJkxTtz6de7egZQx78vsiAT1vg3PZ@auths.local namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICuPK6OfYp7ngZp40Q+Dsrahhks472v6gPIMD0upCRnM
# auths:manual
16 changes: 16 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,19 @@ jobs:
uses: ./
with:
fail-on-unsigned: true

# TODO: Enable after first signed release (just release X.Y.Z runs auths artifact sign dist/index.js)
# verify-artifacts:
# runs-on: ubuntu-latest
# needs: build-and-test
# steps:
# - uses: actions/checkout@v4
# with:
# fetch-depth: 0
#
# - name: Verify dist/index.js attestation
# uses: ./
# with:
# identity-bundle: ... # provide bundle path or inline JSON
# artifact-paths: 'dist/index.js'
# fail-on-unattested: true
72 changes: 61 additions & 11 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Triggered by: python scripts/release.py --push
# (tags vX.Y.Z and pushes, which triggers this workflow)

name: Release

on:
Expand All @@ -13,6 +16,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-node@v4
with:
Expand All @@ -26,33 +31,78 @@ jobs:
- name: Check dist is up to date
run: git diff --exit-code -- dist/ ':!dist/**/*.d.ts.map'

# --- Artifact signing (mirrors auths/auths release workflow) ---
- name: Install auths CLI
run: |
curl -sL https://github.com/auths-dev/auths/releases/latest/download/auths-linux-x86_64.tar.gz | tar xz -C /usr/local/bin

- name: Sign dist/index.js
env:
AUTHS_PASSPHRASE: ${{ secrets.AUTHS_CI_PASSPHRASE }}
AUTHS_CI_KEYCHAIN_B64: ${{ secrets.AUTHS_CI_KEYCHAIN }}
AUTHS_CI_IDENTITY_BUNDLE_B64: ${{ secrets.AUTHS_CI_IDENTITY_BUNDLE }}
AUTHS_KEYCHAIN_BACKEND: file
AUTHS_KEYCHAIN_FILE: /tmp/auths-ci-keychain
run: |
if [ -z "$AUTHS_PASSPHRASE" ] || [ -z "$AUTHS_CI_KEYCHAIN_B64" ] || [ -z "$AUTHS_CI_IDENTITY_BUNDLE_B64" ]; then
echo "::warning::Skipping artifact signing: AUTHS_CI_PASSPHRASE, AUTHS_CI_KEYCHAIN, and AUTHS_CI_IDENTITY_BUNDLE must all be set"
exit 0
fi

printf '%s' "$AUTHS_CI_KEYCHAIN_B64" | tr -d '[:space:]' | base64 -d > /tmp/auths-ci-keychain
mkdir -p /tmp/auths-identity
printf '%s' "$AUTHS_CI_IDENTITY_BUNDLE_B64" | tr -d '[:space:]' | base64 -d | tar -xz -C /tmp/auths-identity

if ! git -C /tmp/auths-identity rev-parse --git-dir > /dev/null 2>&1; then
echo "::warning::Skipping artifact signing: AUTHS_CI_IDENTITY_BUNDLE does not contain a valid git repository"
exit 0
fi

auths artifact sign dist/index.js \
--device-key ci-release-device \
--note "GitHub Actions release — ${GITHUB_REF_NAME}" \
--repo /tmp/auths-identity

echo "Signed dist/index.js → dist/index.js.auths.json"

- name: Generate SHA256 checksums
run: |
cd dist
sha256sum index.js > index.js.sha256
if [ -f index.js.auths.json ]; then
sha256sum index.js.auths.json >> index.js.sha256
fi
cat index.js.sha256

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
make_latest: true
files: |
dist/index.js.auths.json
dist/index.js.sha256
body: |
## Auths Verify GitHub Action

Verify commit signatures in your CI pipeline using [Auths](https://github.com/auths-dev/auths) identity keys.

### Features
- Verifies SSH commit signatures against an allowed signers file or identity bundle
- Auto-downloads the `auths` CLI at runtime
- SHA256 checksum verification on downloaded binaries
- Supports `pull_request` and `push` events with automatic commit range detection
- GitHub Step Summary with per-commit verification results
- Optional PR comments with fix instructions for unsigned commits
- Skips merge commits and GPG-signed commits by default
Verify commit signatures and artifact attestations in your CI pipeline using [Auths](https://github.com/auths-dev/auths) identity keys.

### Usage

```yaml
- uses: auths-dev/auths-verify-github-action@v1
- uses: auths-dev/auths-verify-github-action@${{ github.ref_name }}
with:
allowed-signers: '.auths/allowed_signers'
```

**New: Artifact verification**
```yaml
- uses: auths-dev/auths-verify-github-action@${{ github.ref_name }}
with:
identity-bundle: ${{ secrets.AUTHS_IDENTITY_BUNDLE }}
artifact-paths: 'dist/*.tar.gz'
```

See the [README](https://github.com/auths-dev/auths-verify-github-action#readme) for full configuration options.

- name: Update floating major tag
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ dist/**/*.d.ts.map

# Local tool directories
.deepeval/
.flow/
16 changes: 16 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ inputs:
description: 'GitHub token used to post the PR comment (required when post-pr-comment is true)'
required: false
default: ''
artifact-paths:
description: 'Glob patterns for artifact files to verify, one per line (e.g., "dist/*.tar.gz")'
required: false
default: ''
artifact-attestation-dir:
description: 'Directory containing .auths.json attestation files (default: alongside artifacts)'
required: false
default: ''
fail-on-unattested:
description: 'Fail the action if any artifact lacks a valid attestation'
required: false
default: 'true'

outputs:
verified:
Expand All @@ -51,6 +63,10 @@ outputs:
description: 'Number of commits that passed verification'
failed:
description: 'Number of commits that failed verification'
artifacts-verified:
description: 'Whether all artifacts were verified (true/false)'
artifact-results:
description: 'JSON array of per-artifact verification results'

runs:
using: 'node20'
Expand Down
20 changes: 20 additions & 0 deletions dist/__tests__/artifact-integration.test.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Integration tests for artifact verification in main.ts run() flow.
*
* Since run() is called at module load time, we use jest.isolateModules
* to re-import the module with different mock configurations per test.
*/
declare let mockInputs: Record<string, string>;
declare let mockMultilineInputs: Record<string, string[]>;
declare let mockOutputs: Record<string, string>;
declare let mockFailed: string[];
declare let mockWarnings: string[];
declare let mockGlobFiles: string[];
declare let mockArtifactResults: any[];
declare let mockVerifyCommitsResult: any[];
declare const mockVerifyCommits: jest.Mock<any, any, any>;
declare const mockEnsureAuthsInstalled: jest.Mock<any, any, any>;
declare const mockVerifyArtifact: jest.Mock<any, any, any>;
declare const mockRunPreflightChecks: jest.Mock<any, any, any>;
declare function resetMockState(): void;
declare function runMain(): Promise<void>;
Loading
Loading