8000 Merge branch 'main' into ww/codecov · tetsuo-cpp/sigstore-python@2f307bf · GitHub
[go: up one dir, main page]

Skip to content

Commit 2f307bf

Browse files
authored
Merge branch 'main' into ww/codecov
2 parents b05c90d + 1216ea0 commit 2f307bf

File tree

8 files changed

+202
-75
lines changed

8 files changed

+202
-75
lines changed

.github/workflows/depsreview.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#
2+
# Copyright 2022 The Sigstore Authors.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
name: 'Dependency Review'
16+
on: [pull_request]
17+
18+
permissions:
19+
contents: read
20+
21+
jobs:
22+
dependency-review:
23+
name: License and Vulnerability Scan
24+
uses: sigstore/community/.github/workflows/reusable-dependency-review.yml@9b1b5aca605f92ec5b1bf3681b1e61b3dbc420cc

.github/workflows/release.yml

Lines changed: 123 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,131 @@
1+
name: Release
2+
13
on:
24
release:
35
types:
46
- published
57

6-
name: release
7-
8-
permissions:
9-
# Needed to access the workflow's OIDC identity.
10-
id-token: write
11-
12-
# Needed to upload release assets.
13-
contents: write
14-
158
jobs:
16-
pypi:
17-
name: Build, sign and publish release to PyPI
9+
build:
10+
name: Build and sign artifacts
11+
runs-on: ubuntu-latest
12+
permissions:
13+
id-token: write
14+
outputs:
15+
hashes: ${{ steps.hash.outputs.hashes }}
16+
steps:
17+
- uses: actions/checkout@d171c3b028d844f2bf14e9fdec0c58114451e4bf
18+
19+
- uses: actions/setup-python@7f80679172b057fc5e90d70d197929d454754a5a
20+
21+
- name: deps
22+
run: python -m pip install -U build
23+
24+
- name: build
25+
run: python -m build
26+
27+
- name: sign
28+
run: |
29+
mkdir -p smoketest-artifacts
30+
31+
# we smoke-test sigstore by installing each of the distributions
32+
# we've built in a fresh environment and using each to sign and
33+
# verify for itself, using the ambient OIDC identity
34+
for dist in dist/*; do
35+
dist_base="$(basename "${dist}")"
36+
37+
python -m venv smoketest-env
38+
39+
./smoketest-env/bin/python -m pip install "${dist}"
40+
41+
# NOTE: signing artifacts currently go in a separate directory,
42+
# to avoid confusing the package uploader (which otherwise tries
43+
# to upload them to PyPI and fails). Future versions of twine
44+
# and the gh-action-pypi-publish action should support these artifacts.
45+
./smoketest-env/bin/python -m \
46+
sigstore sign "${dist}" \
47+
--output-signature smoketest-artifacts/"${dist_base}.sig" \
48+
--output-certificate smoketest-artifacts/"${dist_base}.crt"
49+
50+
./smoketest-env/bin/python -m \
51+
sigstore verify "${dist}" \
52+
--cert "smoketest-artifacts/${dist_base}.crt" \
53+
--signature "smoketest-artifacts/${dist_base}.sig" \
54+
--cert-oidc-issuer https://token.actions.githubusercontent.com
55+
56+
rm -rf smoketest-env
57+
done
58+
59+
- name: Generate hashes for provenance
60+
shell: bash
61+
id: hash
62+
run: |
63+
# sha256sum generates sha256 hash for all artifacts.
64+
# base64 -w0 encodes to base64 and outputs on a single line.
65+
# sha256sum artifact1 artifact2 ... | base64 -w0
66+
echo "::set-output name=hashes::$(sha256sum ./dist/* | base64 -w0)"
67+
68+
- name: Upload built packages
69+
uses: actions/upload-artifact@v3
70+
with:
71+
name: built-packages
72+
path: ./dist/
73+
if-no-files-found: warn
74+
75+
- name: Upload smoketest-artifacts
76+
uses: actions/upload-artifact@v3
77+
with:
78+
name: smoketest-artifacts
79+
path: smoketest-artifacts/
80+
if-no-files-found: warn
81+
82+
generate-provenance:
83+
needs: [build]
84+
name: Generate build provenance
85+
permissions:
86+
actions: read # To read the workflow path.
87+
id-token: write # To sign the provenance.
88+
contents: write # To add assets to a release.
89+
# Currently this action needs to be referred by tag. More details at:
90+
# https://github.com/slsa-framework/slsa-github-generator#verification-of-provenance
91+
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.2.1
92+
with:
93+
attestation-name: provenance-sigstore-${{ github.event.release.tag_name }}.intoto.jsonl
94+
base64-subjects: "${{ needs.build.outputs.hashes }}"
95+
upload-assets: true
96+
97+
release-pypi:
98+
needs: [build, generate-provenance]
99+
runs-on: ubuntu-latest
100+
permissions: {}
101+
steps:
102+
- name: Download artifacts diretories # goes to current working directory
103+
uses: actions/download-artifact@v3
104+
105+
- name: publish
106+
uses: pypa/gh-action-pypi-publish@717ba43cfbb0387f6ce311b169a825772f54d295
107+
with:
108+
user: __token__
109+
password: ${{ secrets.PYPI_TOKEN }}
110+
packages_dir: built-packages/
111+
112+
release-github:
113+
needs: [build, generate-provenance]
18114
runs-on: ubuntu-latest
115+
permissions:
116+
# Needed to upload release assets.
117+
contents: write
19118
steps:
20-
- uses: actions/checkout@d171c3b028d844f2bf14e9fdec0c58114451e4bf
21-
22-
- uses: actions/setup-python@7f80679172b057fc5e90d70d197929d454754a5a
23-
24-
- name: deps
25-
run: python -m pip install -U build
26-
27-
- name: build
28-
run: python -m build
29-
30-
- name: sign
31-
run: |
32-
mkdir -p smoketest-artifacts
33-
34-
# we smoke-test sigstore by installing each of the distributions
35-
# we've built in a fresh environment and using each to sign and
36-
# verify for itself, using the ambient OIDC identity
37-
for dist in dist/*; do
38-
dist_base="$(basename "${dist}")"
39-
40-
python -m venv smoketest-env
41-
42-
./smoketest-env/bin/python -m pip install "${dist}"
43-
44-
# NOTE: signing artifacts currently go in a separate directory,
45-
# to avoid confusing the package uploader (which otherwise tries
46-
# to upload them to PyPI and fails). Future versions of twine
47-
# and the gh-action-pypi-publish action should support these artifacts.
48-
./smoketest-env/bin/python -m \
49-
sigstore sign "${dist}" \
50-
--output-signature smoketest-artifacts/"${dist_base}.sig" \
51-
--output-certificate smoketest-artifacts/"${dist_base}.crt"
52-
53-
./smoketest-env/bin/python -m \
54-
sigstore verify "${dist}" \
55-
--cert "smoketest-artifacts/${dist_base}.crt" \
56-
--signature "smoketest-artifacts/${dist_base}.sig" \
57-
--cert-oidc-issuer https://token.actions.githubusercontent.com \
58-
59-
rm -rf smoketest-env
60-
done
61-
62-
- name: publish
63-
uses: pypa/gh-action-pypi-publish@717ba43cfbb0387f6ce311b169a825772f54d295
64-
with:
65-
user: __token__
66-
password: ${{ secrets.PYPI_TOKEN }}
67-
68-
- name: upload artifacts to github
69-
# Confusingly, this action also supports updating releases, not
70-
# just creating them. This is what we want here, since we've manually
71-
# created the release that triggered the action.
72-
uses: softprops/action-gh-release@v1
73-
with:
74-
# dist/ contains the built packages, which smoketest-artifacts/
75-
# contains the signatures and certificates.
76-
files: |
77-
dist/*
78-
smoketest-artifacts/*
119+
- name: Download artifacts diretories # goes to current working directory
120+
uses: actions/download-artifact@v3
121+
122+
- name: Upload artifacts to github
123+
# Confusingly, this action also supports updating releases, not
124+
# just creating them. This is what we want here, since we've manually
125+
# created the release that triggered the action.
126+
uses: softprops/action-gh-release@v1
127+
with:
128+
# smoketest-artifacts/ contains the signatures and certificates.
129+
files: |
130+
built-packages/*
131+
smoketest-artifacts/*

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ sigstore-python
55
![CI](https://github.com/sigstore/sigstore-python/workflows/CI/badge.svg)
66
[![PyPI version](https://badge.fury.io/py/sigstore.svg)](https://pypi.org/project/sigstore)
77
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/sigstore/sigstore-python/badge)](https://api.securityscorecards.dev/projects/github.com/sigstore/sigstore-python)
8+
[![SLSA](https://slsa.dev/images/gh-badge-level3.svg)](https://slsa.dev/)
89
<!--- @end-badges@ --->
910

1011
⚠️ This project is not ready for general-purpose use! ⚠️
@@ -305,6 +306,13 @@ Everyone interacting with this project is expected to follow the
305306
Should you discover any security issues, please refer to sigstore's [security
306307
process](https://github.com/sigstore/.github/blob/main/SECURITY.md).
307308

309+
### SLSA Provenance
310+
This project emits a SLSA provenance on its release! This enables you to verify the integrity
311+
of the downloaded artifacts and ensured that the binary's code really comes from this source code.
312+
313+
To do so, please follow the instructions [here](https://github.com/slsa-framework/slsa-github-generator#verification-of-provenance).
314+
315+
308316
## Info
309317

310318
`sigstore-python` is developed as part of the [`sigstore`](https://sigstore.dev) project.

install/requirements.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ requests==2.28.1 \
166166
--hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \
167167
--hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349
168168
# via sigstore
169-
securesystemslib==0.24.0 \
170-
--hash=sha256:28ea9c44956b73cfe1400703ae11de5107f6d7c62f4463da1ccb63097bf85d5b \
171-
--hash=sha256:793b5028b70dfeed1c1e25d8834ac87710a0b4637e7efa6cd368f3df91d7f878
169+
securesystemslib==0.25.0 \
170+
--hash=sha256:04bc11593edd68405939d3dfc318080bfb31f1ebb5d81c7911914b42dfd4bf2f \
171+
--hash=sha256:10d5a066e70cb87704c9bf2cef1ef6d8a06fab5ef7602dd59c26d06251317a11
172172
# via sigstore
173173
sigstore==0.6.7 \
174174
--hash=sha256:8ddb5d0dbca2464bf6033a53817d251080170764557ef941697284d1c7d2f0fb \
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-----BEGIN PUBLIC KEY-----
2+
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8gEDKNme8AnXuPBgHjrtXdS6miHq
3+
c24CRblNEOFpiJRngeq8Ko73Y+K18yRYVf1DXD4AVLwvKyzdNdl5n0jUSQ==
4+
-----END PUBLIC KEY-----

sigstore/_store/ctfe_2022.staging.pub

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-----BEGIN PUBLIC KEY-----
2+
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEh99xuRi6slBFd8VUJoK/rLigy4bY
3+
eSYWO/fE6Br7r0D8NpMI94+A63LR/WvLxpUUGBpY8IJA3iU2telag5CRpA==
4+
-----END PUBLIC KEY-----

test/conftest.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,44 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import os
1516
from pathlib import Path
1617
from typing import Tuple
1718

1819
import pytest
1920

21+
from sigstore._internal.oidc.ambient import (
22+
AmbientCredentialError,
23+
GitHubOidcPermissionCredentialError,
24+
detect_credential,
25+
)
26+
2027
_ASSETS = (Path(__file__).parent / "assets").resolve()
2128
assert _ASSETS.is_dir()
2229

2330

31+
def _is_ambient_env():
32+
try:
33+
token = detect_credential()
34+
if token is None:
35+
return False
36+
except GitHubOidcPermissionCredentialError:
37+
# On GitHub Actions, forks do not have access to OIDC identities.
38+
# We differentiate this case from other GitHub credential errors,
39+
# since it's a case where we want to skip (i.e. return False).
40+
if os.getenv("GITHUB_EVENT_NAME") == "pull_request":
41+
return False
42+
return True
43+
except AmbientCredentialError:
44+
# If ambient credential detection raises, then we *are* in an ambient
45+
# environment but one that's been configured incorrectly. We
46+
# pass this through, so that the CI fails appropriately rather than
47+
# silently skipping the faulty tests.
48+
return True
49+
50+
return True
51+
52+
2453
def pytest_addoption(parser):
2554
parser.addoption(
2655
"--skip-online",
@@ -34,12 +63,17 @@ def pytest_runtest_setup(item):
3463
pytest.skip(
3564
"skipping test that requires network connectivity due to `--skip-online` flag"
3665
)
66+
elif "ambient_oidc" in item.keywords and not _is_ambient_env():
67+
pytest.skip("skipping test that requires an ambient OIDC credential")
3768

3869

3970
def pytest_configure(config):
4071
config.addinivalue_line(
4172
"markers", "online: mark test as requiring network connectivity"
4273
)
74+
config.addinivalue_line(
75+
"markers", "ambient_oidc: mark test as requiring an ambient OIDC identity"
76+
)
4377

4478

4579
@pytest.fixture

test/test_sign.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ def test_signer_staging():
3131

3232

3333
@pytest.mark.online
34+
@pytest.mark.ambient_oidc
3435
@pytest.mark.parametrize("signer", [Signer.production(), Signer.staging()])
3536
def test_sign_rekor_entry_consistent(signer):
3637
token = detect_credential()
37-
if token is None:
38-
pytest.skip("no ambient credentials; skipping")
38+
assert token is not None
3939

4040
payload = secrets.token_bytes(32)
4141
expected_entry = signer.sign(payload, token).log_entry

0 commit comments

Comments
 (0)
0