Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SCAI reusable actions (KubeCon NA '23 Demo) #13

Merged
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
59 changes: 59 additions & 0 deletions .github/actions/scai-gen-assert/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: "SCAI AttributeAssertion generator"
description: "Generates a SCAI AttributeAssertion with evidence"
inputs:
attribute:
description: "The attribute being asserted"
required: true
evidence-file:
description: "The file containing the evidence. This action assumes the evidence was an artifact uploaded during a previous step, unless otherwise specified."
required: true
evidence-path:
description: "The path to the evidence file. Defaults to GITHUB_WORKSPACE."
required: false
default: "$GITHUB_WORKSPACE"
evidence-type:
description: "The media type of the evidence"
required: optional
default: "application/json"
download-evidence:
description: "Flag to download the evidence artifact"
required: false
default: 'true'
assertion-name:
description: "The artifact name of the unsigned SCAI AttributeAssertion. The file must have the .json extension. Defaults to <attribute>-assert.json when not specified."
required: false
default: "scai-assertion.json"
assertion-path:
description: "The path to save the generated assertion"
default: "$GITHUB_WORKSPACE/temp"
outputs:
assertion-name:
description: "Filename of the generated AttributeAssertion"
value: ${{ steps.scai-gen-assert.outputs.assertion-name }}

runs:
using: "composite"
steps:
- name: Get the evidence artifact
id: get-evidence
if: ${{ inputs.download-evidence == 'true' }}
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: "${{ inputs.evidence-file }}"

- name: Generate ResourceDescriptor for evidence
id: gen-rd
uses: ./.github/actions/scai-gen-rd
with:
name: "${{ inputs.evidence-file }}"
path: "${{ inputs.evidence-path }}"
media-type: "${{ inputs.evidence-type }}"
rd-name: "${{ inputs.evidence-file }}-desc.json"

- name: Run scai-gen assert
id: scai-gen-assert
shell: bash
run: |
mkdir -p ${{ inputs.assertion-path }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly out of scope but perhaps the output dir creation should be handled by scai-gen assert so that the action's usable even without mkdir. IDK if mkdir is aliased / supported on Windows, for example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good point, and shouldn't be too hard to implement, I hope. What I'll do is merge this PR so I can start testing this with my test build. I have some documentation for the demo in-flight (nothing major) that I think would fit well into a "make the demo more legible/usable" PR.

scai-gen assert -e ${{ steps.gen-rd.outputs.file-rd-name }} -o ${{ inputs.assertion-path }}/${{ inputs.assertion-name }} ${{ inputs.attribute}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use the full flag names instead of the short ones? I think it makes it more readable in this context and possibly more maintainable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I'll make these changes as part of a follow-up PR that focuses on readability and usability of the demo, so I can unblock testing on the implementer end.

echo "assertion-name=${{ inputs.assertion-path }}/${{ inputs.assertion-name }}" >> "$GITHUB_OUTPUT"
68 changes: 68 additions & 0 deletions .github/actions/scai-gen-rd/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: "in-toto ResourceDescriptor generator"
description: "Generates an in-toto ResourceDescriptor for a local file or remote resource"
inputs:
is-file:
description: "Flag indicating whether the resource is a local file or remote. Default is `is-file=true`."
required: false
default: 'true'
name:
description: "The name of the resource file."
required: true
path:
description: "The path to the resource file. Defaults to GITHUB_WORKSPACE."
required: false
default: "$GITHUB_WORKSPACE"
uri:
description: "The URI of the remote resource."
required: false
default: "https://github.com/$GITHUB_REPOSITORY/commit/$GITHUB_SHA"
digest:
description: "The digest associated with the remote resource (hex-encoded)"
required: false
default: ""
hash-alg:
description: "The hash algorithm used to compute the digest associated with the remote resource."
required: false
default: "sha256"
location:
description: "The download location of the file"
required: false
default: "https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
media-type:
description: "The media type of the file"
required: false
default: "text/plain"
rd-name:
description: "The name of the output ResourceDescriptor file. The file must have the .json extension."
required: true
rd-path:
description: "The path to save the generated descriptor"
default: "$GITHUB_WORKSPACE/temp"
outputs:
file-rd-name:
description: "Filename of the generated ResourceDescriptor"
value: ${{ steps.scai-gen-rd-file.outputs.rd-name }}
remote-rd-name:
description: "Filename of the generated ResourceDescriptor"
value: ${{ steps.scai-gen-rd-remote.outputs.rd-name }}

runs:
using: "composite"
steps:
- name: Run scai-gen rd file
id: scai-gen-rd-file
if: ${{ inputs.is-file == 'true' }}
shell: bash
run: |
mkdir -p ${{ inputs.rd-path }}
scai-gen rd file -n ${{ inputs.name }} -l ${{ inputs.location }} -t ${{ inputs.media-type }} -o ${{ inputs.rd-path }}/${{ inputs.rd-name }} ${{ inputs.path }}/${{ inputs.name }}
echo "rd-name=${{ inputs.rd-path }}/${{ inputs.rd-name }}" >> "$GITHUB_OUTPUT"

- name: Run scai-gen rd remote
id: scai-gen-rd-remote
if: ${{ inputs.is-file == 'false' }}
shell: bash
run: |
mkdir -p ${{ inputs.rd-path }}
scai-gen rd remote -n ${{ inputs.name }} -d ${{ inputs.digest }} -g ${{ inputs.hash-alg }} -o ${{ inputs.rd-path }}/${{ inputs.rd-name }} ${{ inputs.uri }}
echo "rd-name=${{ inputs.rd-path }}/${{ inputs.rd-name }}" >> "$GITHUB_OUTPUT"
41 changes: 41 additions & 0 deletions .github/actions/scai-gen-report/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: "scai-gen-report"
description: "Generates a signed SCAI AttributeReport"
inputs:
subject:
description: "The subject ResourceDescriptor. This action currently assumes a single subject."
required: true
attr-assertions:
description: "The names of the SCAI AttributeAssertions to be listed in the Report. This action assumes the Assertions were generated using the scai-gen-assert action."
required: true
report-name:
description: "The name of the AttributeReport file"
required: false
default: "scai-report.json"
report-path:
description: "The directory to place the in-toto SCAI predicate attestation"
required: false
default: "$GITHUB_WORKSPACE/temp"
outputs:
report-name:
description: "Filename of the generated AttributeReport"
value: ${{ steps.scai-gen-report.outputs.report-name }}

runs:
using: "composite"
steps:
- name: Run scai-gen rd file
id: scai-gen-report
shell: bash
run: |
mkdir -p ${{ inputs.report-path }}
scai-gen report -s ${{ inputs.subject }} -o ${{ inputs.report-path }}/${{ inputs.report-name }} ${{ inputs.attr-assertions }}
echo "report-name=${{ inputs.report-path }}/${{ inputs.report-name }}" >> "$GITHUB_OUTPUT"
ls ${{ inputs.report-path }}

- name: Upload the signed SCAI AttributeReport
id: upload-assert
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: ${{ inputs.report-name }}
path: ${{ steps.scai-gen-report.outputs.report-name }}
retention-days: 15
46 changes: 46 additions & 0 deletions .github/actions/scai-gen-sigstore/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: "in-toto Sigstore signer"
description: "Generates a signed in-toto Attestation using cosign, and uploads it to the public Rekor log"
inputs:
save-signed:
description: "Flag indicating whether to save the signed attestation as a local artifact (using actions/upload-artifact). Default is `save-signed=true`."
required: false
default: 'true'
statement-file:
description: "The name of the unsigned in-toto Statement file."
required: true
statement-path:
description: "The path to the statement-file. Defaults to GITHUB_WORKSPACE."
required: false
default: "$GITHUB_WORKSPACE"
attestation-name:
description: "The name of the DSSE formatted signed in-toto Attestation file."
required: true
attestation-path:
description: "The directory to place the signed in-toto Attestation."
required: false
default: "$GITHUB_WORKSPACE/attestations"

outputs:
attestation-name:
description: "Filename of the generated signed in-toto Attestation"
value: ${{ steps.sign.outputs.attestation-name }}

runs:
using: "composite"
steps:
- name: Sign and upload in-toto Statement
id: sign
shell: bash
run: |
mkdir -p ${{ inputs.attestation-path }}
scai-gen sigstore -o ${{ inputs.attestation-path}}/${{ inputs.attestation-name }} ${{ inputs.statement-path }}/${{ inputs.statement-name }}
echo "attestation-name=${{ inputs.attestation-path }}/${{ inputs.attestation-name }}" >> "$GITHUB_OUTPUT"

- name: Save the signed in-toto Attestation
if: ${{ inputs.save-signed == 'true' }}
id: upload-signed
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: ${{ steps.sign.inputs.attestation-name }}
path: ${{ steps.sign.outputs.attestation-name }}
retention-days: 15
64 changes: 64 additions & 0 deletions .github/workflows/test-e2e-flow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Test composite actions on SBOM+SLSA example
on:
push:
branch:
- main
paths:
- "scai-gen/**"
# Want to trigger these tests whenever the Go CLI or
# APIs are modified
pull_request:
paths:
- "scai-gen/**"

jobs:
sbom-slsa-ex:
runs-on: ubuntu-22.04
steps:
- name: Install Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe
with:
go-version: 1.20.x

- name: Checkout updated scai-gen CLI tools
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11

- name: Setup Env
run: |
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH

- name: Install scai-gen CLI tools
shell: bash
run: |
go install ./scai-gen
mkdir -p temp

- name: Generate SBOM SCAI AttributeAssertion
id: gen-sbom-assert
uses: ./.github/actions/scai-gen-assert
with:
attribute: "HasSBOM"
evidence-file: "pdo_client_wawaka.spdx.json"
evidence-path: "examples/sbom+slsa/metadata"
evidence-type: "application/json"
download-evidence: false
assertion-name: "hassbom-assertion.json"

- name: Generate SLSA Provenance SCAI AttributeAssertion
id: gen-slsa-assert
uses: ./.github/actions/scai-gen-assert
with:
attribute: "HasSLSA"
evidence-file: "pdo_client_wawaka.provenance.json"
evidence-path: "examples/sbom+slsa/metadata"
evidence-type: "application/vnd.in-toto.provenance+dsse"
download-evidence: false
assertion-name: "hasslsa-assertion.json"

- name: Generate SCAI AttributeReport
id: gen-sbom-slsa-report
uses: ./.github/actions/scai-gen-report
with:
subject: "examples/sbom+slsa/metadata/container-img-desc.json"
attr-assertions: "${{ steps.gen-sbom-assert.outputs.assertion-name }} ${{ steps.gen-slsa-assert.outputs.assertion-name }}"
report-name: "evidence-collection.scai.json"
42 changes: 42 additions & 0 deletions .github/workflows/test-sigstore-integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Test Sigstore integration
on:
# Want to trigger these tests whenever the Sigstore command
# is modified and PR is closed and merged.
# Reason: OIDC token access constraints in PRs
pull_request:
paths:
- "scai-gen/cmd/sigstore.go"
types:
- closed

jobs:
sigstore:
if: github.event.pull_request.merged == true
runs-on: ubuntu-22.04
permissions:
id-token: write # Needed for signing
steps:
- name: Install Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe
with:
go-version: 1.20.x

- name: Checkout updated scai-gen CLI tools
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11

- name: Setup Env
run: |
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH

- name: Install scai-gen CLI tools
shell: bash
run: |
go install ./scai-gen

- name: Sign and upload SCAI report (Sigstore)
id: sign-report
shell: bash
uses: ./.github/actions/scai-gen-sigstore
with:
statement-file: examples/sbom+slsa/metadata/evidence-collection.scai.json
attestation-name: evidence-collection.scai.sig.json
Loading
Loading