Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c321849480 | |||
| c65e8d4737 | |||
| ffbe5726c3 | |||
| 1ddccb76ab | |||
| a25a27cab8 | |||
| e18a799f23 | |||
| 5b44f686c6 | |||
| 9c10929297 | |||
| 3f6ab60ba4 | |||
| f7e1c5d786 | |||
| 088247d089 | |||
| 6bc26cfc5e | |||
| 59d89421af |
@@ -28,11 +28,11 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
id: checkout
|
||||
uses: actions/checkout@v6.0.2
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup Node.js
|
||||
id: setup-node
|
||||
uses: actions/setup-node@v6.2.0
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: npm
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
- if: ${{ failure() && steps.diff.outcome == 'failure' }}
|
||||
name: Upload Artifact
|
||||
id: upload
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: dist
|
||||
path: dist/
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
|
||||
- name: Setup Node.js
|
||||
id: setup-node
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
with:
|
||||
node-version-file: .node-version
|
||||
cache: npm
|
||||
|
||||
@@ -32,19 +32,19 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
id: checkout
|
||||
uses: actions/checkout@v6.0.2
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Initialize CodeQL
|
||||
id: initialize
|
||||
uses: github/codeql-action/init@v4
|
||||
uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
source-root: src
|
||||
|
||||
- name: Autobuild
|
||||
id: autobuild
|
||||
uses: github/codeql-action/autobuild@v4
|
||||
uses: github/codeql-action/autobuild@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
id: analyze
|
||||
uses: github/codeql-action/analyze@v4
|
||||
uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
name: GitHub Sigstore Prober
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# run every 5 minutes, as often as Github Actions allows
|
||||
- cron: '*/5 * * * *'
|
||||
|
||||
jobs:
|
||||
prober:
|
||||
if: github.repository_owner == 'actions'
|
||||
permissions:
|
||||
attestations: write
|
||||
id-token: write
|
||||
secrets: inherit
|
||||
uses: ./.github/workflows/prober.yml
|
||||
with:
|
||||
sigstore: github
|
||||
@@ -0,0 +1,18 @@
|
||||
name: Public-Good Sigstore Prober
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# run every 5 minutes, as often as Github Actions allows
|
||||
- cron: '*/5 * * * *'
|
||||
|
||||
jobs:
|
||||
prober:
|
||||
if: github.repository_owner == 'actions'
|
||||
permissions:
|
||||
attestations: write
|
||||
id-token: write
|
||||
secrets: inherit
|
||||
uses: ./.github/workflows/prober.yml
|
||||
with:
|
||||
sigstore: public-good
|
||||
@@ -0,0 +1,84 @@
|
||||
name: Prober Workflow
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
sigstore:
|
||||
description: 'Which Sigstore instance to use for signing'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
probe:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
attestations: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Request OIDC Token
|
||||
run: |
|
||||
curl "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=nobody" \
|
||||
-H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \
|
||||
-H "Accept: application/json; api-version=2.0" \
|
||||
-H "Content-Type: application/json" \
|
||||
--silent | jq -r '.value' | jq -R 'split(".") | .[0],.[1] | @base64d | fromjson'
|
||||
|
||||
- name: Create artifact
|
||||
run: |
|
||||
date > artifact
|
||||
|
||||
- name: Attest build provenance
|
||||
uses: actions/attest@main
|
||||
env:
|
||||
INPUT_PRIVATE-SIGNING: ${{ inputs.sigstore == 'github' && 'true' || 'false' }}
|
||||
with:
|
||||
subject-path: artifact
|
||||
|
||||
- name: Verify build artifact
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh attestation verify ./artifact --owner "$GITHUB_REPOSITORY_OWNER"
|
||||
|
||||
- name: Upload build artifact
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
path: "artifact"
|
||||
|
||||
- name: Report attestation prober success
|
||||
if: ${{ success() }}
|
||||
uses: masci/datadog@c1b14660479f44f1049b08274d1bfaae9405cbae # v2.0.0
|
||||
with:
|
||||
api-key: "${{ secrets.DATADOG_API_KEY }}"
|
||||
service-checks: |
|
||||
- check: "attestation-integration.actions.prober"
|
||||
status: 0
|
||||
host_name: github.com
|
||||
tags:
|
||||
- "catalog_service:${{ secrets.CATALOG_SERVICE }}"
|
||||
- "service:${{ secrets.CATALOG_SERVICE }}"
|
||||
- "stamp:${{ secrets.STAMP }}"
|
||||
- "env:production"
|
||||
- "repo:${{ github.repository }}"
|
||||
- "team:${{ secrets.TEAM }}"
|
||||
- "sigstore:${{ inputs.sigstore }}"
|
||||
|
||||
- name: Report attestation prober failure
|
||||
if: ${{ failure() }}
|
||||
uses: masci/datadog@c1b14660479f44f1049b08274d1bfaae9405cbae # v2.0.0
|
||||
with:
|
||||
api-key: "${{ secrets.DATADOG_API_KEY }}"
|
||||
service-checks: |
|
||||
- check: "attestation-integration.actions.prober"
|
||||
message: "${{ github.repository_owner }} failed prober check"
|
||||
status: 2
|
||||
host_name: github.com
|
||||
tags:
|
||||
- "catalog_service:${{ secrets.CATALOG_SERVICE }}"
|
||||
- "service:${{ secrets.CATALOG_SERVICE }}"
|
||||
- "stamp:${{ secrets.STAMP }}"
|
||||
- "env:production"
|
||||
- "repo:${{ github.repository }}"
|
||||
- "team:${{ secrets.TEAM }}"
|
||||
- "sigstore:${{ inputs.sigstore }}"
|
||||
@@ -48,11 +48,11 @@ the inputs you provide:
|
||||
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
| Mode | When Used | Description |
|
||||
| -------------- | ------------------------------------------------------ | ------------------------------------------------ |
|
||||
| **Provenance** | No `sbom-path` or predicate inputs | Auto-generates [SLSA build provenance][10] |
|
||||
| **SBOM** | `sbom-path` is provided | Creates attestation from SPDX or CycloneDX SBOM |
|
||||
| **Custom** | `predicate-type`/`predicate`/`predicate-path` provided | User-supplied predicate |
|
||||
| Mode | When Used | Description |
|
||||
| -------------- | ------------------------------------------------------ | ----------------------------------------------- |
|
||||
| **Provenance** | No `sbom-path` or predicate inputs | Auto-generates [SLSA build provenance][10] |
|
||||
| **SBOM** | `sbom-path` is provided | Creates attestation from SPDX or CycloneDX SBOM |
|
||||
| **Custom** | `predicate-type`/`predicate`/`predicate-path` provided | User-supplied predicate |
|
||||
|
||||
<!-- markdownlint-enable MD013 -->
|
||||
|
||||
@@ -159,7 +159,7 @@ See [action.yml](action.yml)
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
| Name | Description | Example |
|
||||
| ------------------- | -------------------------------------------------------------- | ------------------------------------------------ |
|
||||
| -------------------- | -------------------------------------------------------------- | ------------------------------------------------ |
|
||||
| `attestation-id` | GitHub ID for the attestation | `123456` |
|
||||
| `attestation-url` | URL for the attestation summary | `https://github.com/foo/bar/attestations/123456` |
|
||||
| `bundle-path` | Absolute path to the file containing the generated attestation | `/tmp/attestation.json` |
|
||||
@@ -320,9 +320,25 @@ fully-qualified image name (e.g. "ghcr.io/user/app" or
|
||||
"acme.azurecr.io/user/app"). Do NOT include a tag as part of the image name --
|
||||
the specific image being attested is identified by the supplied digest.
|
||||
|
||||
If the `push-to-registry` option is set to true, the Action will also
|
||||
emit an Artifact Metadata Storage Record. If you do not want to emit a
|
||||
storage record, set `create-storage-record` to `false`.
|
||||
#### Artifact Metadata Storage Records
|
||||
|
||||
When generating a build provenance attestation, if the `push-to-registry` option
|
||||
is set to true, the Action will also emit an
|
||||
[Artifact Metadata Storage Record](https://docs.github.com/en/rest/orgs/artifact-metadata?apiVersion=2022-11-28#create-artifact-metadata-storage-record).
|
||||
Storage records enrich artifact metadata by capturing storage related details,
|
||||
such as which registry an image is hosted on and whether it's marked as active.
|
||||
|
||||
If you do not want to emit a storage record, set `create-storage-record` to
|
||||
`false`.
|
||||
|
||||
> **NOTE**: Storage records can only be created for artifacts built from
|
||||
> [organization-owned](https://docs.github.com/en/organizations/collaborating-with-groups-in-organizations/about-organizations)
|
||||
> repositories.
|
||||
|
||||
Artifacts associated with a storage record can be viewed by navigating to the
|
||||
`Linked Artifacts` page in your organization:
|
||||
`https://github.com/orgs/YOUR_ORG/artifacts` (replace `YOUR_ORG` with your
|
||||
organization name).
|
||||
|
||||
> **NOTE**: When pushing to Docker Hub, please use "docker.io" as the registry
|
||||
> portion of the image name.
|
||||
|
||||
@@ -67,7 +67,8 @@ describe('index', () => {
|
||||
pushToRegistry: false,
|
||||
createStorageRecord: true,
|
||||
showSummary: true,
|
||||
privateSigning: false
|
||||
privateSigning: false,
|
||||
skipAttestationStore: false
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
+6
-3
@@ -120862,7 +120862,8 @@ const createAttestation = async (subjects, predicate, opts) => {
|
||||
predicateType: predicate.type,
|
||||
predicate: predicate.params,
|
||||
sigstore: opts.sigstoreInstance,
|
||||
token: opts.githubToken
|
||||
token: opts.githubToken,
|
||||
skipWrite: opts.skipAttestationStore
|
||||
});
|
||||
const result = attestation;
|
||||
if (subjects.length === 1 && opts.pushToRegistry) {
|
||||
@@ -121159,7 +121160,8 @@ async function run(inputs) {
|
||||
pushToRegistry: inputs.pushToRegistry,
|
||||
createStorageRecord: inputs.createStorageRecord,
|
||||
subjectVersion: inputs.subjectVersion,
|
||||
githubToken: inputs.githubToken
|
||||
githubToken: inputs.githubToken,
|
||||
skipAttestationStore: inputs.skipAttestationStore
|
||||
});
|
||||
logAttestation(subjects, att, sigstoreInstance);
|
||||
// Write attestation bundle to output file
|
||||
@@ -121304,7 +121306,8 @@ const inputs = {
|
||||
showSummary: getBooleanInput('show-summary'),
|
||||
githubToken: getInput('github-token'),
|
||||
// undocumented -- not part of public interface
|
||||
privateSigning: ['true', 'True', 'TRUE', '1'].includes(getInput('private-signing'))
|
||||
privateSigning: ['true', 'True', 'TRUE', '1'].includes(getInput('private-signing')),
|
||||
skipAttestationStore: ['true', 'True', 'TRUE', '1'].includes(getInput('skip-attestation-store'))
|
||||
};
|
||||
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
|
||||
run(inputs);
|
||||
|
||||
Generated
+435
-504
File diff suppressed because it is too large
Load Diff
+6
-6
@@ -87,23 +87,23 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@jest/globals": "^30.2.0",
|
||||
"@jest/globals": "^30.3.0",
|
||||
"@sigstore/mock": "^0.11.0",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/make-fetch-happen": "^10.0.4",
|
||||
"@types/node": "^25.3.0",
|
||||
"@types/node": "^25.5.0",
|
||||
"@vercel/ncc": "^0.38.4",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-jest": "^29.15.0",
|
||||
"jest": "^30.2.0",
|
||||
"jest": "^30.3.0",
|
||||
"js-yaml": "^4.1.1",
|
||||
"markdownlint-cli": "^0.47.0",
|
||||
"markdownlint-cli": "^0.48.0",
|
||||
"nock": "^13.5.6",
|
||||
"prettier": "^3.8.1",
|
||||
"ts-jest": "^29.4.6",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.56.1",
|
||||
"undici": "^7.20.0"
|
||||
"typescript-eslint": "^8.57.1",
|
||||
"undici": "^7.24.4"
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -28,6 +28,7 @@ export const createAttestation = async (
|
||||
createStorageRecord: boolean
|
||||
subjectVersion?: string
|
||||
githubToken: string
|
||||
skipAttestationStore?: boolean
|
||||
}
|
||||
): Promise<AttestResult> => {
|
||||
// Sign provenance w/ Sigstore
|
||||
@@ -36,7 +37,8 @@ export const createAttestation = async (
|
||||
predicateType: predicate.type,
|
||||
predicate: predicate.params,
|
||||
sigstore: opts.sigstoreInstance,
|
||||
token: opts.githubToken
|
||||
token: opts.githubToken,
|
||||
skipWrite: opts.skipAttestationStore
|
||||
})
|
||||
|
||||
const result: AttestResult = attestation
|
||||
|
||||
@@ -21,6 +21,9 @@ const inputs: RunInputs = {
|
||||
// undocumented -- not part of public interface
|
||||
privateSigning: ['true', 'True', 'TRUE', '1'].includes(
|
||||
core.getInput('private-signing')
|
||||
),
|
||||
skipAttestationStore: ['true', 'True', 'TRUE', '1'].includes(
|
||||
core.getInput('skip-attestation-store')
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -39,6 +39,7 @@ export type RunInputs = SubjectInputs &
|
||||
githubToken: string
|
||||
showSummary: boolean
|
||||
privateSigning: boolean
|
||||
skipAttestationStore: boolean
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
@@ -99,7 +100,8 @@ export async function run(inputs: RunInputs): Promise<void> {
|
||||
pushToRegistry: inputs.pushToRegistry,
|
||||
createStorageRecord: inputs.createStorageRecord,
|
||||
subjectVersion: inputs.subjectVersion,
|
||||
githubToken: inputs.githubToken
|
||||
githubToken: inputs.githubToken,
|
||||
skipAttestationStore: inputs.skipAttestationStore
|
||||
})
|
||||
|
||||
logAttestation(subjects, att, sigstoreInstance)
|
||||
|
||||
Reference in New Issue
Block a user