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

feat: source archive builder #3587

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 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
71 changes: 71 additions & 0 deletions .github/workflows/builder_source-archive_slsa3.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Copyright 2023 SLSA Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: SLSA Source archive builder

permissions: {}

on:
workflow_call:
inputs:
formats:
description: >
A list of archive formats to generate. Supported: "zip" and "tar.gz".
Each format must be separated by a space or on a new line.

Example: "zip tar.gz"
required: true
type: string
upload-assets:
description: >
If true, provenance is uploaded to a GitHub release for new tags.
The only value supported is 'true'. The workflow will fail if set to 'false'.
required: false
type: boolean
default: true
Copy link
Contributor

Choose a reason for hiding this comment

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

Why have this option at all? Can't you hard code the value?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm thinking in terms of backward compatibility, eg if we ever want to support non-release archive generation. This would require folks being able to set whether they want to upload or not, for example. By default it could be that it does not upload, like in other workflows we have. Let me think a bit more, I'm less convinced than I was yesterday :)

rekor-log-public:
description: "Allow publication of your repository name on the public Rekor log"
required: false
type: boolean
default: false

jobs:
slsa-setup:
permissions:
id-token: write # For token creation.
outputs:
slsa-token: ${{ steps.generate.outputs.slsa-token }}
runs-on: ubuntu-latest
steps:
- name: Generate the token
id: generate
uses: slsa-framework/slsa-github-generator/actions/delegator/setup-generic@main
with:
slsa-workflow-recipient: "delegator_generic_slsa3.yml"
slsa-rekor-log-public: ${{ inputs.rekor-log-public }}
slsa-runner-label: "ubuntu-latest"
slsa-build-action-path: "./internal/builders/archive"
slsa-workflow-inputs: ${{ toJson(inputs) }}

slsa-run:
needs: [slsa-setup]
permissions:
id-token: write # For signing.
contents: read # For repo checkout of private repos.
actions: read # For getting workflow run on private repos.
uses: slsa-framework/slsa-github-generator/.github/workflows/delegator_generic_slsa3.yml@main
with:
slsa-token: ${{ needs.slsa-setup.outputs.slsa-token }}

# TODO(): upload attestation as release assets using needs.slsa-run.outputs.attestations-download-name and attestations-download-sha256

Check failure on line 71 in .github/workflows/builder_source-archive_slsa3.yml

View workflow job for this annotation

GitHub Actions / yamllint

71:138 [new-line-at-end-of-file] no new line character at the end of file
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will add this later this week

1 change: 1 addition & 0 deletions .github/workflows/pre-submit.actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ jobs:
- ./actions/delegator/setup-generic
- .github/actions/verify-token
- .github/actions/detect-workflow-js
- internal/builders/archive
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

<!-- toc -->

- [Unreleased](#unreleased)
- [Unreleased: Source archive builder](#unreleased-source-archive-builder)
- [v2.0.0](#v200)
- [v2.0.0: Breaking Change: upload-artifact and download-artifact](#v200-breaking-change-upload-artifact-and-download-artifact)
- [v2.0.0: Breaking Change: attestation-name Workflow Input and Output](#v200-breaking-change-attestation-name-workflow-input-and-output)
Expand Down Expand Up @@ -102,6 +104,12 @@ Use the format "X.Y.Z: Go builder" etc. for format headers to avoid header name
duplication."
-->

## Unreleased

### Unreleased: Source archive builder

- **New**: A [Source archive builder](https://github.com/slsa-framework/slsa-github-generator/tree/main/internal/builders/archive) to build source archives with provenance and upload them as release assets.

## v2.0.0

### v2.0.0: Breaking Change: upload-artifact and download-artifact
Expand Down
66 changes: 66 additions & 0 deletions internal/builders/archive/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Copyright 2023 SLSA Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

SHELL := /bin/bash
ACTION_NAME = $(shell basename "$$(pwd)")

.PHONY: help
help: ## Shows all targets and help from the Makefile (this message).
@echo "$(ACTION_NAME) Makefile"
@echo "Usage: make [COMMAND]"
@echo ""
@grep --no-filename -E '^([/a-z.A-Z0-9_%-]+:.*?|)##' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = "(:.*?|)## ?"}; { \
if (length($$1) > 0) { \
printf " \033[36m%-20s\033[0m %s\n", $$1, $$2; \
} else { \
if (length($$2) > 0) { \
printf "%s\n", $$2; \
} \
} \
}'

node_modules/.installed: package.json package-lock.json
npm ci
touch node_modules/.installed

.PHONY: action
action: node_modules/.installed ## Builds the action.
npm run build

.PHONY: package
package: action ## Builds the distribution package.
npm run package

.PHONY: clean
clean:
rm -rf dist lib node_modules

## Tools
#####################################################################

.PHONY: format
format: node_modules/.installed ## Formats code.
npm run format

## Testing
#####################################################################

.PHONY: unit-test
unit-test: node_modules/.installed ## Runs all unit tests.
npm run test

.PHONY: lint
lint: node_modules/.installed ## Runs eslint.
npm run lint
1 change: 1 addition & 0 deletions internal/builders/archive/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TODO

Check failure on line 1 in internal/builders/archive/README.md

View workflow job for this annotation

GitHub Actions / markdownlint

MD047/single-trailing-newline Files should end with a single newline character [Detail: "", Context: ""]

Check failure on line 1 in internal/builders/archive/README.md

View workflow job for this annotation

GitHub Actions / markdownlint

MD041/first-line-heading First line in a file should be a top-level heading [Detail: "", Context: "TODO"]
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

will do this later this week

117 changes: 117 additions & 0 deletions internal/builders/archive/__tests__/inputs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright 2023 SLSA Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
* @fileoverview Tests for inputs.ts
*/

import * as inputs from "../src/inputs";

describe("parseFormats", () => {
it("empty value", async () => {
const value = "";
expect(() => {
const formats = inputs.parseFormats(value);
}).toThrow();
});

it("space value", async () => {
const value = " ";
expect(() => {
const formats = inputs.parseFormats(value);
}).toThrow();
});

it("eol value", async () => {
const value = `
`;
expect(() => {
const formats = inputs.parseFormats(value);
}).toThrow();
});

it("eol + space value", async () => {
const value = `

`;
expect(() => {
const formats = inputs.parseFormats(value);
}).toThrow();
});

it("one line one format", async () => {
const value = "zip";
const formats = inputs.parseFormats(value);
expect(formats).toEqual(["zip"]);
});

it("one line one format with space", async () => {
const value = " zip ";
const formats = inputs.parseFormats(value);
expect(formats).toEqual(["zip"]);
});

it("one line two format", async () => {
const value = "zip tar.gz";
const formats = inputs.parseFormats(value);
expect(formats).toEqual(["zip", "tar.gz"]);
});

it("one line two format with space", async () => {
const value = " zip tar.gz ";
const formats = inputs.parseFormats(value);
expect(formats).toEqual(["zip", "tar.gz"]);
});

it("two line two format with tab", async () => {
const value = `zip
tar.gz`;
const formats = inputs.parseFormats(value);
expect(formats).toEqual(["zip", "tar.gz"]);
});

it("two line two format with tab and space", async () => {
const value = ` zip
tar.gz `;
const formats = inputs.parseFormats(value);
expect(formats).toEqual(["zip", "tar.gz"]);
});
});

describe("formatsToAPI", () => {
it("empty formats", async () => {
const formats: string[] = [];
expect(() => {
const actual = inputs.formatsToAPI(formats);
}).toThrow();
});

it("two valid formats", async () => {
const formats = ["zip", "tar.gz"];
const actual = inputs.formatsToAPI(formats);
expect(actual).toEqual(["zipball", "tarball"]);
});

it("tarball format", async () => {
const formats = ["tar.gz"];
const actual = inputs.formatsToAPI(formats);
expect(actual).toEqual(["tarball"]);
});

it("zip format", async () => {
const formats = ["zip"];
const actual = inputs.formatsToAPI(formats);
expect(actual).toEqual(["zipball"]);
});
});
46 changes: 46 additions & 0 deletions internal/builders/archive/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Copyright 2024 SLSA Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: SLSA3 Builder internal wrapper
description: SLSA3 Builder internal wrapper

inputs:
slsa-workflow-inputs:
description: "All the inputs formatted as a JSON map"
required: true

slsa-layout-file:
description: "Location to store the layout content"
required: true

# Unused secret inputs.
slsa-workflow-secret1: {}
slsa-workflow-secret2: {}
slsa-workflow-secret3: {}
slsa-workflow-secret4: {}
slsa-workflow-secret5: {}
slsa-workflow-secret6: {}
slsa-workflow-secret7: {}
slsa-workflow-secret8: {}
slsa-workflow-secret9: {}
slsa-workflow-secret10: {}
slsa-workflow-secret11: {}
slsa-workflow-secret12: {}
slsa-workflow-secret13: {}
slsa-workflow-secret14: {}
slsa-workflow-secret15: {}

runs:
using: "node20"
main: "dist/index.js"
Loading
Loading