From 356e53c497856814c458ddbbaa815737e429b571 Mon Sep 17 00:00:00 2001 From: Tom Herbers Date: Tue, 24 Sep 2024 01:03:20 +0200 Subject: [PATCH 1/6] .github: add LICENSE --- .github/LICENSE | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/LICENSE diff --git a/.github/LICENSE b/.github/LICENSE new file mode 100644 index 0000000..c9b5304 --- /dev/null +++ b/.github/LICENSE @@ -0,0 +1,37 @@ +BSD 2-Clause License + +The code of Project Gluon may be distributed under the following terms, unless +noted otherwise in individual files or subtrees. + +Copyright (c) Project Gluon +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +OpenWrt is licensed under the terms of the GNU General Public License Version 2, +which can be found at openwrt/LICENSE after the OpenWrt repository has been +obtained. This applies to the following repositories: + + * openwrt + * packages/openwrt + * packages/routing + * packages/luci From 9a36dec1b64c238a4104a0cd97d03ca24791e485 Mon Sep 17 00:00:00 2001 From: Tom Herbers Date: Tue, 24 Sep 2024 00:54:23 +0200 Subject: [PATCH 2/6] ci: skip signing in forks and warn user Based on: https://github.com/freifunk-darmstadt/site-ffda/commit/b334be45338ea18e0e6e026c65397c8d332c2ab4 --- .github/build-meta.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/build-meta.sh b/.github/build-meta.sh index e7f15fc..0d51688 100644 --- a/.github/build-meta.sh +++ b/.github/build-meta.sh @@ -3,6 +3,7 @@ set -euxo pipefail SCRIPT_DIR="$(dirname "$0")" +UPSTREAM_REPO_NAME="freifunk-rhein-neckar/site-ffrn" # Get Git short hash for repo at $SCRIPT_DIR GIT_SHORT_HASH="$(git -C "$SCRIPT_DIR" rev-parse --short HEAD)" @@ -159,6 +160,14 @@ if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then SIGN_MANIFEST="0" fi +# Signing should only happen when pushed to the upstream repository. +# Skip this step for the pipeline to succeed but inform the user. +if [ "${GITHUB_REPOSITORY,,}" != "${UPSTREAM_REPO_NAME,,}" ] && [ "$SIGN_MANIFEST" != "0" ]; then + SIGN_MANIFEST="0" + + echo "::warning::Skip manifest signature due to action running in fork." +fi + # Determine Version to use RELEASE_VERSION="${RELEASE_VERSION:-$DEFAULT_RELEASE_VERSION}" From 2c8aa49115fe0e42e351cb918ff31ccaec4eab9f Mon Sep 17 00:00:00 2001 From: Tom Herbers Date: Tue, 24 Sep 2024 00:56:51 +0200 Subject: [PATCH 3/6] ci: skip deployment in forks Based on: https://github.com/freifunk-darmstadt/site-ffda/commit/08a00c21f355b2c52525f71b4586de60d344d8c5 --- .github/build-meta.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/build-meta.sh b/.github/build-meta.sh index 0d51688..a830abd 100644 --- a/.github/build-meta.sh +++ b/.github/build-meta.sh @@ -168,6 +168,13 @@ if [ "${GITHUB_REPOSITORY,,}" != "${UPSTREAM_REPO_NAME,,}" ] && [ "$SIGN_MANIFES echo "::warning::Skip manifest signature due to action running in fork." fi +# We should neither deploy in a fork, as the workflow is hard-coding our firmware-server +if [ "$GITHUB_REPOSITORY" != "$UPSTREAM_REPO_NAME" ] && [ "$DEPLOY" != "0" ]; then + DEPLOY="0" + + echo "::warning::Skip deployment due to action running in fork." +fi + # Determine Version to use RELEASE_VERSION="${RELEASE_VERSION:-$DEFAULT_RELEASE_VERSION}" From cf61030f4c3071cc1b488c35d25a03ae057cd242 Mon Sep 17 00:00:00 2001 From: Tom Herbers Date: Tue, 24 Sep 2024 00:59:34 +0200 Subject: [PATCH 4/6] ci: attest build provenance for images Based on: https://github.com/freifunk-darmstadt/site-ffda/commit/e9eb098e2b20e7fd8de4ae1bbaade2c6f68f1d26 --- .github/workflows/build.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f780b97..96b0c09 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -198,6 +198,9 @@ jobs: runs-on: ubuntu-22.04 if: > needs.targets.outputs.targets != '[]' + permissions: + id-token: write + attestations: write steps: - uses: actions/checkout@v4 @@ -271,6 +274,14 @@ jobs: gluon-path: "gluon-gha-data/gluon" hardware-target: ${{ matrix.target }} + - name: Attest Image Build Provenance + if: ${{ needs.build-meta.outputs.create-release != '0' }} + uses: actions/attest-build-provenance@v1 + with: + subject-path: | + "gluon-gha-data/gluon/output/images/sysupgrade/*" + "gluon-gha-data/gluon/output/images/other/*" + "gluon-gha-data/gluon/output/images/factory/*" manifest: needs: [build, build-meta, targets] @@ -547,6 +558,8 @@ jobs: github.event_name == 'push' permissions: contents: write + id-token: write + attestations: write steps: - uses: actions/checkout@v4 @@ -590,6 +603,12 @@ jobs: gluon-gha-data/release-artifacts/build-meta.txt gluon-gha-data/release-notes.md + - name: Attest Release Artifact Build Provenance + uses: actions/attest-build-provenance@v1 + with: + subject-path: | + gluon-gha-data/release-artifacts/* + - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: From 618a2ab0c266ae4494ca5299a0d2377c172d9c59 Mon Sep 17 00:00:00 2001 From: Tom Herbers Date: Tue, 24 Sep 2024 01:02:39 +0200 Subject: [PATCH 5/6] contrib: add script for fetching attestation Based on: https://github.com/freifunk-darmstadt/site-ffda/commit/81d70d3c067a5ad6ec224229ad29b991849ff7a8 --- contrib/load-attestation.py | 80 +++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 contrib/load-attestation.py diff --git a/contrib/load-attestation.py b/contrib/load-attestation.py new file mode 100644 index 0000000..7ac5eff --- /dev/null +++ b/contrib/load-attestation.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# SPDX-License-Identifier: MIT + +import sys +import json +import os +import requests +import base64 +import hashlib +import argparse + +DEFAULT_OWNER = "freifunk-rhein-neckar" +DEFAULT_REPO = "site-ffrn" + +def parse_arguments(): + parser = argparse.ArgumentParser(description='Load and print attestation from a GitHub API.') + parser.add_argument('-o', '--owner', help='Owner of the repository', required=False, default=DEFAULT_OWNER) + parser.add_argument('-r', '--repo', help='Repository name', required=False, default=DEFAULT_REPO) + parser.add_argument('file_path', help='Path to the attestation file') + return parser.parse_args() + +def get_file_sha256(file_path): + sha256 = hashlib.sha256() + with open(file_path, "rb") as f: + while True: + data = f.read(65536) + if not data: + break + sha256.update(data) + return sha256.hexdigest() + +def load_attestation_from_gh_api(owner, repo, file_sha256): + url = f"https://api.github.com/repos/{owner}/{repo}/attestations/sha256:{file_sha256}" + headers = { + "Accept": "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", + } + response = requests.get(url, headers=headers) + + if response.status_code != 200: + print(f"Failed to load attestation from {url}") + sys.exit(1) + + print("Got attestation from GitHub API") + + return response.json() + +def print_attestation(data): + dsse_envelope = data.get("attestations", [{}])[0].get("bundle", {}).get("dsseEnvelope", {}) + if "payload" not in dsse_envelope: + print("No payload in attestation") + sys.exit(1) + + decoded_dsse_payload = base64.b64decode(dsse_envelope["payload"]) + + dsse_object = json.loads(decoded_dsse_payload) + ci_filename = dsse_object["subject"][0]["name"] + ci_hashes = dsse_object["subject"][0]["digest"] + print(f"Artifact: {ci_filename}") + for hash in ci_hashes.keys(): + print(f" {hash}: {ci_hashes[hash]}") + + predicate = dsse_object["predicate"] + build_definition = predicate["buildDefinition"] + run_details = predicate["runDetails"] + + build_commit = build_definition["resolvedDependencies"][0]["digest"]["gitCommit"] + print(f" Commit: {build_commit}") + print(f" Run: {run_details["metadata"]["invocationId"]}") + + +if __name__ == "__main__": + # Command: load-attestation.py [-o -r ] + args = parse_arguments() + + print(f"Fetching attestation for {args.file_path} from {args.owner}/{args.repo}") + file_hash = get_file_sha256(args.file_path) + attestation = load_attestation_from_gh_api(args.owner, args.repo, file_hash) + print_attestation(attestation) From c9980b754d1dcc16072918ac03d3bb16ddd9d36f Mon Sep 17 00:00:00 2001 From: Tom Herbers Date: Tue, 24 Sep 2024 01:09:16 +0200 Subject: [PATCH 6/6] contrib/load-attestation.py: fix invalid f-string Based on: https://github.com/freifunk-darmstadt/site-ffda/commit/150e5ea2b18a093ba6d4fb94dbb49b4154008570 --- contrib/load-attestation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 contrib/load-attestation.py diff --git a/contrib/load-attestation.py b/contrib/load-attestation.py old mode 100644 new mode 100755 index 7ac5eff..c9c0f1d --- a/contrib/load-attestation.py +++ b/contrib/load-attestation.py @@ -67,8 +67,8 @@ def print_attestation(data): build_commit = build_definition["resolvedDependencies"][0]["digest"]["gitCommit"] print(f" Commit: {build_commit}") - print(f" Run: {run_details["metadata"]["invocationId"]}") - + invocation_id = run_details["metadata"]["invocationId"] + print(f" Run: {invocation_id}") if __name__ == "__main__": # Command: load-attestation.py [-o -r ]