Skip to content

Commit 96f29bc

Browse files
committed
Collapse more functions into main doc, add more trailing commas, minor calculation adjustments
The primary justification for collapsing everything back into the main document (aside from there only being a single caller for each function) is that it makes verifying that we didn't miss anything easier -- as you scan the document, for each field that contains a "load-bearing" URL (first https://in-toto.io/Statement/v1, then https://slsa.dev/provenance/v1, and finally https://actions.github.io/buildtypes/workflow/v1), if you open the URL it describes the expected format, fields, and values, and with them all here and in-order, they're *much* easier to match up and validate to be correct and exhaustive. Granted, that will change over time as we shove more and more (optional) data into this document so that it includes a more complete picture, but for now, this is makes it really easy to double check our work (and the end result is no less organized; for example, the `externalParameters` are still all grouped together under a suitable heading describing what their purpose is). I also made some minor changes to the way values were calculated, especially in the `workflow` block, but very related to the above justification: now the way we calculate the values matches the way they're described in https://actions.github.io/buildtypes/workflow/v1 (specifically using the exact fields parsed in the exact ways they suggest). We will probably deviate from that over time (as suggested by a new "TODO" comment I included), but at least this way our baseline matches theirs and the delta will be easier to track. Additionally, I removed the `(env.GITHUB_CONTEXT | fromjson) as $github` line from here, because I think that's more appropriate behavior for the caller (and added back the explicit function arguments). This will be more clearly meaningful in my follow-up commit adding a basic test.
1 parent 24e679e commit 96f29bc

File tree

1 file changed

+73
-72
lines changed

1 file changed

+73
-72
lines changed

provenance.jq

Lines changed: 73 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,78 @@
1-
# input: "build" object (with "buildId" top level key)
2-
# output: list of image tags
3-
def tags:
4-
[
5-
.source.arches[].tags[],
6-
.source.arches[].archTags[],
7-
.build.img
8-
]
9-
;
10-
11-
# input: "tags" object with image digest and platform arguments
12-
# output: json object for in-toto provenance subject field
13-
def subjects($platform; $digest):
14-
($digest | split(":")) as $splitDigest
15-
| {
16-
"name": "pkg:docker/\(.)?platform=\($platform)",
17-
"digest": {
18-
($splitDigest[0]): $splitDigest[1],
19-
}
20-
}
21-
;
22-
23-
# input: GITHUB context
24-
# output: json object for in-toto provenance external parameters field
25-
def github_external_parameters($github):
26-
($github.workflow_ref | ltrimstr($github.repository + "/") | split("@")) as $workflowRefSplit
27-
| {
28-
inputs: $github.event.inputs,
29-
workflow: {
30-
ref: $workflowRefSplit[1],
31-
repository: ($github.server_url + "/" + $github.repository),
32-
path: $workflowRefSplit[0],
33-
digest: { gitCommit: $github.workflow_sha },
34-
}
35-
}
36-
;
37-
381
# input: "build" object with platform and image digest
39-
# output: json object for in-toto provenance statement
40-
def github_actions_provenance:
41-
(env.GITHUB_CONTEXT | fromjson) as $github |
42-
(.source.arches[].platformString | @uri) as $platform |
43-
{
44-
_type: "https://in-toto.io/Statement/v1",
45-
subject: . | tags | map(subjects($platform; $digest)),
46-
predicateType: "https://slsa.dev/provenance/v1",
47-
predicate: {
48-
buildDefinition: {
49-
buildType: "https://actions.github.io/buildtypes/workflow/v1",
50-
externalParameters: github_external_parameters($github),
51-
internalParameters: {
52-
github: {
53-
event_name: $github.event_name,
54-
repository_id: $github.repository_id,
55-
repository_owner_id: $github.repository_owner_id,
56-
runner_environment: "github-hosted"
57-
}
2+
# $github: "github" context; CONTAINS SENSITIVE INFORMATION (https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#github-context)
3+
# $digest: the OCI image digest for the just-built image (normally in .build.resolved.annotations["org.opencontainers.image.ref.name"] but only post-push/regeneration and we haven't pushed yet)
4+
#
5+
# output: in-toto provenance statement (https://slsa.dev/spec/v1.0/provenance)
6+
# see also: https://github.com/actions/buildtypes/tree/main/workflow/v1
7+
def github_actions_provenance($github; $digest):
8+
if $github.event_name != "workflow_dispatch" then error("error: '\($github.event_name)' is not a supported event type for provenance generation") else
9+
{
10+
_type: "https://in-toto.io/Statement/v1",
11+
subject: [
12+
($digest | split(":")) as $splitDigest
13+
| (.source.arches[.build.arch].platformString) as $platform
14+
| (
15+
.source.arches[.build.arch].tags[],
16+
.source.arches[.build.arch].archTags[],
17+
.build.img,
18+
empty # trailing comma
19+
)
20+
| {
21+
# https://github.com/package-url/purl-spec/blob/b33dda1cf4515efa8eabbbe8e9b140950805f845/PURL-TYPES.rst#docker (this matches what BuildKit generates as of 2024-09-18; "oci" would also be a reasonable choice, but would require signer and policy changes to support, and be more complex to generate accurately)
22+
name: "pkg:docker/\(.)?platform=\($platform | @uri)",
23+
digest: { ($splitDigest[0]): $splitDigest[1] },
24+
}
25+
],
26+
predicateType: "https://slsa.dev/provenance/v1",
27+
predicate: {
28+
buildDefinition: {
29+
buildType: "https://actions.github.io/buildtypes/workflow/v1",
30+
externalParameters: {
31+
workflow: {
32+
# TODO this matches how this is documented/suggested in GitHub's buildType documentation, but does not account for the workflow file being in a separate repository at a separate ref from the "source" (which the "workflow_ref" field *does* account for), so that would/will change how we need to calculate these values if we ever do that (something like "^(?<repo>[^/]+/[^/]+)/(?<path>.*)@(?<ref>refs/.*)$" on $github.workflow_ref ?)
33+
ref: $github.ref,
34+
repository: ($github.server_url + "/" + $github.repository),
35+
path: (
36+
$github.workflow_ref
37+
| ltrimstr($github.repository + "/")
38+
| rtrimstr("@" + $github.ref)
39+
| if contains("@") then error("parsing 'workflow_ref' failed: '\(.)'") else . end
40+
),
41+
# not required, but useful/important (and potentially but unlikely different from $github.sha used in resolvedDependencies below):
42+
digest: { gitCommit: $github.workflow_sha },
43+
},
44+
inputs: $github.event.inputs, # https://docs.github.com/en/webhooks/webhook-events-and-payloads#workflow_dispatch
45+
},
46+
internalParameters: {
47+
github: {
48+
event_name: $github.event_name,
49+
repository_id: $github.repository_id,
50+
repository_owner_id: $github.repository_owner_id,
51+
runner_environment: "github-hosted",
52+
},
53+
},
54+
resolvedDependencies: [
55+
{
56+
uri: "git+\($github.server_url)/\($github.repository)@\($github.ref)",
57+
digest: { "gitCommit": $github.sha },
58+
},
59+
# TODO figure out a way to include resolved action SHAs from "uses:" expressions
60+
# TODO include more resolved dependencies
61+
empty # tailing comma
62+
],
5863
},
59-
resolvedDependencies: [{
60-
uri: ("git+"+$github.server_url+"/"+$github.repository+"@"+$github.ref),
61-
digest: { "gitCommit": $github.sha }
62-
}]
63-
},
64-
runDetails: {
65-
# builder.id identifies the transitive closure of the trusted build platform evalution.
66-
# any changes that alter security properties or build level must update this ID and rotate the signing key.
67-
# https://slsa.dev/spec/v1.0/provenance#builder
68-
builder: {
69-
id: ($github.server_url+"/"+$github.workflow_ref),
64+
runDetails: {
65+
# builder.id identifies the transitive closure of the trusted build platform evalution.
66+
# any changes that alter security properties or build level must update this ID and rotate the signing key.
67+
# https://slsa.dev/spec/v1.0/provenance#builder
68+
builder: {
69+
id: ($github.server_url + "/" + $github.workflow_ref),
70+
},
71+
metadata: {
72+
invocationId: "\($github.server_url)/\($github.repository)/actions/runs/\($github.run_id)/attempts/\($github.run_attempt)",
73+
},
7074
},
71-
metadata: {
72-
invocationId: ($github.server_url+"/"+$github.repository+"/actions/runs/"+$github.run_id+"/attempts/"+$github.run_attempt),
73-
}
74-
}
75+
},
7576
}
76-
}
77+
end
7778
;

0 commit comments

Comments
 (0)