Skip to content

Commit 846b66b

Browse files
authored
Merge pull request #26 from herbetom/ci-updates
pull upstream ci updates
2 parents 8a5055d + c9980b7 commit 846b66b

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed

.github/LICENSE

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
BSD 2-Clause License
2+
3+
The code of Project Gluon may be distributed under the following terms, unless
4+
noted otherwise in individual files or subtrees.
5+
6+
Copyright (c) Project Gluon
7+
All rights reserved.
8+
9+
Redistribution and use in source and binary forms, with or without
10+
modification, are permitted provided that the following conditions are met:
11+
12+
1. Redistributions of source code must retain the above copyright notice,
13+
this list of conditions and the following disclaimer.
14+
2. Redistributions in binary form must reproduce the above copyright notice,
15+
this list of conditions and the following disclaimer in the documentation
16+
and/or other materials provided with the distribution.
17+
18+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+
29+
30+
OpenWrt is licensed under the terms of the GNU General Public License Version 2,
31+
which can be found at openwrt/LICENSE after the OpenWrt repository has been
32+
obtained. This applies to the following repositories:
33+
34+
* openwrt
35+
* packages/openwrt
36+
* packages/routing
37+
* packages/luci

.github/build-meta.sh

+16
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
set -euxo pipefail
44

55
SCRIPT_DIR="$(dirname "$0")"
6+
UPSTREAM_REPO_NAME="freifunk-rhein-neckar/site-ffrn"
67

78
# Get Git short hash for repo at $SCRIPT_DIR
89
GIT_SHORT_HASH="$(git -C "$SCRIPT_DIR" rev-parse --short HEAD)"
@@ -159,6 +160,21 @@ if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
159160
SIGN_MANIFEST="0"
160161
fi
161162

163+
# Signing should only happen when pushed to the upstream repository.
164+
# Skip this step for the pipeline to succeed but inform the user.
165+
if [ "${GITHUB_REPOSITORY,,}" != "${UPSTREAM_REPO_NAME,,}" ] && [ "$SIGN_MANIFEST" != "0" ]; then
166+
SIGN_MANIFEST="0"
167+
168+
echo "::warning::Skip manifest signature due to action running in fork."
169+
fi
170+
171+
# We should neither deploy in a fork, as the workflow is hard-coding our firmware-server
172+
if [ "$GITHUB_REPOSITORY" != "$UPSTREAM_REPO_NAME" ] && [ "$DEPLOY" != "0" ]; then
173+
DEPLOY="0"
174+
175+
echo "::warning::Skip deployment due to action running in fork."
176+
fi
177+
162178
# Determine Version to use
163179
RELEASE_VERSION="${RELEASE_VERSION:-$DEFAULT_RELEASE_VERSION}"
164180

.github/workflows/build.yml

+19
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ jobs:
198198
runs-on: ubuntu-22.04
199199
if: >
200200
needs.targets.outputs.targets != '[]'
201+
permissions:
202+
id-token: write
203+
attestations: write
201204
steps:
202205
- uses: actions/checkout@v4
203206

@@ -271,6 +274,14 @@ jobs:
271274
gluon-path: "gluon-gha-data/gluon"
272275
hardware-target: ${{ matrix.target }}
273276

277+
- name: Attest Image Build Provenance
278+
if: ${{ needs.build-meta.outputs.create-release != '0' }}
279+
uses: actions/attest-build-provenance@v1
280+
with:
281+
subject-path: |
282+
"gluon-gha-data/gluon/output/images/sysupgrade/*"
283+
"gluon-gha-data/gluon/output/images/other/*"
284+
"gluon-gha-data/gluon/output/images/factory/*"
274285
275286
manifest:
276287
needs: [build, build-meta, targets]
@@ -547,6 +558,8 @@ jobs:
547558
github.event_name == 'push'
548559
permissions:
549560
contents: write
561+
id-token: write
562+
attestations: write
550563
steps:
551564
- uses: actions/checkout@v4
552565

@@ -590,6 +603,12 @@ jobs:
590603
gluon-gha-data/release-artifacts/build-meta.txt
591604
gluon-gha-data/release-notes.md
592605
606+
- name: Attest Release Artifact Build Provenance
607+
uses: actions/attest-build-provenance@v1
608+
with:
609+
subject-path: |
610+
gluon-gha-data/release-artifacts/*
611+
593612
- name: Create GitHub Release
594613
uses: softprops/action-gh-release@v2
595614
with:

contrib/load-attestation.py

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
# SPDX-License-Identifier: MIT
4+
5+
import sys
6+
import json
7+
import os
8+
import requests
9+
import base64
10+
import hashlib
11+
import argparse
12+
13+
DEFAULT_OWNER = "freifunk-rhein-neckar"
14+
DEFAULT_REPO = "site-ffrn"
15+
16+
def parse_arguments():
17+
parser = argparse.ArgumentParser(description='Load and print attestation from a GitHub API.')
18+
parser.add_argument('-o', '--owner', help='Owner of the repository', required=False, default=DEFAULT_OWNER)
19+
parser.add_argument('-r', '--repo', help='Repository name', required=False, default=DEFAULT_REPO)
20+
parser.add_argument('file_path', help='Path to the attestation file')
21+
return parser.parse_args()
22+
23+
def get_file_sha256(file_path):
24+
sha256 = hashlib.sha256()
25+
with open(file_path, "rb") as f:
26+
while True:
27+
data = f.read(65536)
28+
if not data:
29+
break
30+
sha256.update(data)
31+
return sha256.hexdigest()
32+
33+
def load_attestation_from_gh_api(owner, repo, file_sha256):
34+
url = f"https://api.github.com/repos/{owner}/{repo}/attestations/sha256:{file_sha256}"
35+
headers = {
36+
"Accept": "application/vnd.github+json",
37+
"X-GitHub-Api-Version": "2022-11-28",
38+
}
39+
response = requests.get(url, headers=headers)
40+
41+
if response.status_code != 200:
42+
print(f"Failed to load attestation from {url}")
43+
sys.exit(1)
44+
45+
print("Got attestation from GitHub API")
46+
47+
return response.json()
48+
49+
def print_attestation(data):
50+
dsse_envelope = data.get("attestations", [{}])[0].get("bundle", {}).get("dsseEnvelope", {})
51+
if "payload" not in dsse_envelope:
52+
print("No payload in attestation")
53+
sys.exit(1)
54+
55+
decoded_dsse_payload = base64.b64decode(dsse_envelope["payload"])
56+
57+
dsse_object = json.loads(decoded_dsse_payload)
58+
ci_filename = dsse_object["subject"][0]["name"]
59+
ci_hashes = dsse_object["subject"][0]["digest"]
60+
print(f"Artifact: {ci_filename}")
61+
for hash in ci_hashes.keys():
62+
print(f" {hash}: {ci_hashes[hash]}")
63+
64+
predicate = dsse_object["predicate"]
65+
build_definition = predicate["buildDefinition"]
66+
run_details = predicate["runDetails"]
67+
68+
build_commit = build_definition["resolvedDependencies"][0]["digest"]["gitCommit"]
69+
print(f" Commit: {build_commit}")
70+
invocation_id = run_details["metadata"]["invocationId"]
71+
print(f" Run: {invocation_id}")
72+
73+
if __name__ == "__main__":
74+
# Command: load-attestation.py [-o <owner> -r <repo>] <file-path>
75+
args = parse_arguments()
76+
77+
print(f"Fetching attestation for {args.file_path} from {args.owner}/{args.repo}")
78+
file_hash = get_file_sha256(args.file_path)
79+
attestation = load_attestation_from_gh_api(args.owner, args.repo, file_hash)
80+
print_attestation(attestation)

0 commit comments

Comments
 (0)