Skip to content
Draft
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
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,28 @@ jobs:

- name: Audit production dependencies
run: npm audit --omit=dev --audit-level=high

verify-artifact-action:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 22

- name: Check source syntax
working-directory: github-actions/trustsignal-verify-artifact
run: npm run check

- name: Verify dist alignment
working-directory: github-actions/trustsignal-verify-artifact
run: npm run check:dist

- name: Run local contract tests
working-directory: github-actions/trustsignal-verify-artifact
run: npm run test:local
37 changes: 37 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: TrustSignal Verify Artifact

on:
workflow_dispatch:
push:
branches: ["master"]

jobs:
verify-artifact:
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Build release artifact
run: |
mkdir -p dist
echo "release-$(git rev-parse --short HEAD)" > dist/release.txt

- name: Verify artifact with TrustSignal
id: trustsignal
uses: ./github-actions/trustsignal-verify-artifact
with:
api_base_url: ${{ secrets.TRUSTSIGNAL_API_BASE_URL }}
api_key: ${{ secrets.TRUSTSIGNAL_API_KEY }}
artifact_path: dist/release.txt
source: github-actions
fail_on_mismatch: "true"

- name: Record verification outputs
run: |
echo "Verification ID: ${{ steps.trustsignal.outputs.verification_id }}"
echo "Status: ${{ steps.trustsignal.outputs.status }}"
echo "Receipt ID: ${{ steps.trustsignal.outputs.receipt_id }}"
35 changes: 25 additions & 10 deletions docs/integrations/github-action.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ The GitHub Action does not connect to Supabase directly. TrustSignal persists re
1. The workflow sends an artifact hash or local artifact path through the GitHub Action.
2. The action calls `POST /api/v1/verify` on `api.trustsignal.dev`.
3. TrustSignal validates the request, authenticates the caller, issues a signed receipt, and persists the receipt server-side.
4. The action stores `receiptId` and `receiptSignature` for later verification or audit use.
4. The action writes `verification_id`, `status`, `receipt_id`, and `receipt_signature` as GitHub Actions outputs.
5. Public consumers can inspect the stored receipt through `GET /api/v1/receipt/{receiptId}` or render a compact badge from `GET /api/v1/receipt/{receiptId}/summary`.
6. A later workflow can call `POST /api/v1/receipt/{receiptId}/verify` with an artifact hash to confirm integrity.

Expand All @@ -26,7 +26,7 @@ x-api-key: <trustsignal-api-key>
content-type: application/json
```

Request body:
Request body sent by the action:

```json
{
Expand All @@ -48,20 +48,25 @@ Request body:
}
```

Response fields used by the action:
Response fields used by the action (both snake_case and camelCase variants are accepted):

- `verificationId`
- `receiptId`
- `receiptSignature`
- `status`
| Action output | API field(s) read |
| --- | --- |
| `verification_id` | `verification_id`, `verificationId`, `id`, `receipt_id`, `receiptId` |
| `status` | `status`, `verificationStatus`, `result`, `verified`, `valid`, `match` |
| `receipt_id` | `receipt_id`, `receiptId` |
| `receipt_signature` | `receipt_signature` (string), `receiptSignature` (string or `{ signature }` object) |

The action request enforces a 30-second timeout. An `AbortError` from the timeout is reported
as a clean error message without exposing raw headers or internal service details.

### `GET /api/v1/receipt/{receiptId}`

This public-safe endpoint returns a compact inspection view for artifact receipts. It is intended for receipt drill-down pages and audit references.
This endpoint returns a compact inspection view for artifact receipts. It is intended for receipt drill-down pages and audit references.

### `GET /api/v1/receipt/{receiptId}/summary`

This public-safe endpoint returns a compact display payload for trust centers, evidence panels, and partner dashboards.
This endpoint returns a compact display payload for trust centers, evidence panels, and partner dashboards.

### `POST /api/v1/receipt/{receiptId}/verify`

Expand Down Expand Up @@ -96,8 +101,18 @@ Response fields:
- Row Level Security is enabled on the artifact receipt table as defense in depth.
- Public lookup and summary endpoints are read-only and return safe receipt fields only.
- Later verification remains behind TrustSignal API authentication.
- `fail_on_mismatch: true` (default) provides fail-closed behavior for pipelines that require verified artifacts.

## Validation

- Local contract tests: `npm run test:local` (uses mock fetch, no live API required)
- Dist alignment check: `npm run check:dist` (SHA-256 comparison of `src` and `dist`)
- Live integration test: `npm run test:integration` (skips when credentials are absent)

See `github-actions/trustsignal-verify-artifact/docs/integration.md` for the full integration guide.

## Current Limitations

- The repository includes a local smoke test, but a live deployed integration test remains pending.
- The public verification contract currently accepts `sha256` only.
- GitHub Marketplace publication requires extracting this action into a dedicated public repository with `action.yml` at the repository root.

55 changes: 45 additions & 10 deletions github-actions/trustsignal-verify-artifact/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,68 @@

## Local Validation

Run the lightweight validation checks before opening a change:
Run the complete validation suite before opening a change:

```bash
npm run validate
```

This runs the following checks in order:

1. **`npm run check`** — Node.js syntax check for `src/index.js` and `dist/index.js`.
2. **`npm run check:dist`** — SHA-256 comparison to confirm `dist/index.js` matches `src/index.js`.
3. **`npm run test:local`** — Local action contract test using a mock fetch (no live API required).

Or run each step individually:

```bash
node --check src/index.js
node --check dist/index.js
node scripts/check-dist.js
node scripts/test-local.js
```

Or use package scripts:
## Live Integration Test

To run the end-to-end integration test against a deployed TrustSignal API:

```bash
npm run check
npm run test:local
npm run validate:local
export TRUSTSIGNAL_INTEGRATION_API_BASE_URL=https://api.trustsignal.dev
export TRUSTSIGNAL_INTEGRATION_API_KEY=<your-api-key>
npm run test:integration
```

The test skips cleanly when the environment variables are not set.

## Repository Structure

- `action.yml`: GitHub Action metadata
- `src/`: source implementation
- `dist/`: committed runtime entrypoint for action consumers
- `scripts/`: local validation helpers
- `mock-fetch.js`: fetch mock used by `test-local.js`
- `test-local.js`: local contract test (mock-based)
- `check-dist.js`: dist alignment check
- `integration-test.js`: live integration test (skips without credentials)
- `docs/`: integration-facing documentation
- `integration.md`: verification flow, request/response contract, security notes
- `release-checklist.md`: pre-release and tagging checklist

## Building

```bash
npm run build
```

This copies `src/index.js` to `dist/index.js`. Run `npm run check:dist` afterwards to
confirm alignment.

## Release

See `docs/release-checklist.md` for the complete release process, including:

## Release Basics
- dist alignment verification
- semantic version tagging
- stable major tag maintenance
- GitHub Marketplace publication steps

- Follow semantic versioning.
- Commit updated `dist/index.js` with each release.
- Publish immutable tags such as `v0.1.0` and maintain a major tag such as `v1`.
- GitHub Marketplace publication requires a public repository with `action.yml` at the repository root.
46 changes: 27 additions & 19 deletions github-actions/trustsignal-verify-artifact/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,42 +168,50 @@ TrustSignal gives security and release teams a consistent way to verify artifact

## Current Limitations

- Local validation uses a fetch mock rather than a live TrustSignal deployment.
- GitHub Marketplace publication requires this action to be published from a dedicated public repository root with `action.yml` at the top level.
- Live end-to-end validation against a deployed TrustSignal API should remain part of the release process.

## Local Validation

Run the lightweight validation checks with:
Run the complete validation suite with:

```bash
npm run validate
```

This runs a syntax check, a dist alignment check (SHA-256 comparison of `src` and `dist`), and the local contract test. No live API is required.

Individual commands:

```bash
node --check src/index.js
node --check dist/index.js
node scripts/check-dist.js
node scripts/test-local.js
```

Or use the package scripts:
## Live Integration Test

To validate against a deployed TrustSignal API:

```bash
npm run check
npm run test:local
npm run validate:local
export TRUSTSIGNAL_INTEGRATION_API_BASE_URL=https://api.trustsignal.dev
export TRUSTSIGNAL_INTEGRATION_API_KEY=<your-api-key>
npm run test:integration
```

The test skips cleanly when the environment variables are not set. See `docs/integration.md` for details.

## Versioning Guidance

- Follow semantic versioning.
- Publish immutable release tags for each shipped version.
- Maintain a major tag such as `v1` for stable consumers.

## Release Checklist

- Commit the built `dist/index.js` artifact with every release.
- Create signed or otherwise controlled release tags according to your release process.
- Update documentation when the public API contract or output mapping changes.
- Publish immutable release tags for each shipped version (e.g., `v0.2.0`).
- Maintain a stable major tag such as `v1` for consumers who want automatic non-breaking updates.
- See `docs/release-checklist.md` for the complete release process.

## Roadmap
## Release Checklist Summary

- Add a live integration test against a deployed TrustSignal verification endpoint
- Publish the action from a dedicated public repository root
- Add example workflows for release pipelines and provenance retention patterns
- Confirm `src/index.js` changes are intentional.
- Run `npm run build` and then `npm run validate` to confirm dist alignment.
- Create an immutable version tag and update the stable major tag.
- Confirm `action.yml` references `dist/index.js` as the action entrypoint.
- Update documentation when the API contract or output field mapping changes.
30 changes: 22 additions & 8 deletions github-actions/trustsignal-verify-artifact/dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,28 @@ async function callVerificationApi({ apiBaseUrl, apiKey, artifactHash, artifactP
const endpoint = `${apiBaseUrl}/api/v1/verify`;
const payload = buildVerificationRequest({ artifactHash, artifactPath, source });

const response = await fetch(endpoint, {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-api-key': apiKey
},
body: JSON.stringify(payload)
});
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30_000);

let response;
try {
response = await fetch(endpoint, {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-api-key': apiKey
},
body: JSON.stringify(payload),
signal: controller.signal
});
} catch (error) {
if (error && error.name === 'AbortError') {
throw new Error('TrustSignal API request timed out after 30 seconds');
}
throw error;
} finally {
clearTimeout(timeout);
}

const responseBody = await parseJsonResponse(response);

Expand Down
Loading
Loading