Merge branch 'trunk' into cli-9496

This commit is contained in:
benebsiny 2024-08-17 12:05:17 +08:00
commit 216c283e03
71 changed files with 1413 additions and 695 deletions

View file

@ -299,7 +299,7 @@ jobs:
rpmsign --addsign dist/*.rpm
- name: Attest release artifacts
if: inputs.environment == 'production'
uses: actions/attest-build-provenance@5e9cb68e95676991667494a6a4e59b8a2f13e1d0 # v1.3.3
uses: actions/attest-build-provenance@310b0a4a3b0b78ef57ecda988ee04b132db73ef8 # v1.4.1
with:
subject-path: "dist/gh_*"
- name: Run createrepo

View file

@ -286,7 +286,7 @@ func IssueStatus(client *Client, repo ghrepo.Interface, options IssueStatusOptio
}
}
}
}`
}`
variables := map[string]interface{}{
"owner": repo.RepoOwner(),

View file

@ -152,13 +152,13 @@ func StatusCheckRollupGraphQLWithCountByState() string {
contexts {
checkRunCount,
checkRunCountsByState {
state,
count
state,
count
},
statusContextCount,
statusContextCountsByState {
state,
count
state,
count
}
}
}

View file

@ -8,6 +8,8 @@ triage role. The initial expectation is that the person in the role for the week
Review and label [open issues missing either the `enhancement`, `bug`, or `docs` label](https://github.com/cli/cli/issues?q=is%3Aopen+is%3Aissue+-label%3Abug%2Cenhancement%2Cdocs+).
Any issue that is accepted to be done as either an `enhancement`, `bug`, or `docs` requires explicit Acceptance Criteria in a comment on the issue before `needs-triage` label is removed.
To be considered triaged, `enhancement` issues require at least one of the following additional labels:
- `core`: reserved for the core CLI team

View file

@ -4,6 +4,9 @@ POV: your team at GitHub is interested in shipping a new command in `gh`.
This document outlines the process the CLI team prefers for helping ensure success both for your new feature and the CLI project as a whole.
> [!NOTE]
> External contributors, please see [CONTRIBUTING.md](/.github/CONTRIBUTING.md).
## Step 0: Create an extension
Even if you want to see your code merged into `gh`, you should start with [an extension](https://docs.github.com/en/github-cli/github-cli/creating-github-cli-extensions) written in Go and leveraging [go-gh](https://github.com/cli/go-gh). Though `gh` extensions can be written in any language, we treat Go as a first class experience and ship a library of helpers for extensions written in Go.

11
go.mod
View file

@ -15,12 +15,12 @@ require (
github.com/cli/oauth v1.0.1
github.com/cli/safeexec v1.0.1
github.com/cpuguy83/go-md2man/v2 v2.0.4
github.com/creack/pty v1.1.21
github.com/creack/pty v1.1.23
github.com/distribution/reference v0.5.0
github.com/gabriel-vasile/mimetype v1.4.4
github.com/gabriel-vasile/mimetype v1.4.5
github.com/gdamore/tcell/v2 v2.5.4
github.com/google/go-cmp v0.6.0
github.com/google/go-containerregistry v0.20.0
github.com/google/go-containerregistry v0.20.2
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/gorilla/websocket v1.5.3
github.com/hashicorp/go-multierror v1.1.1
@ -70,9 +70,8 @@ require (
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/docker/cli v24.0.0+incompatible // indirect
github.com/docker/cli v27.1.1+incompatible // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/docker v24.0.9+incompatible // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
@ -158,7 +157,7 @@ require (
go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect
golang.org/x/mod v0.19.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/sys v0.22.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 // indirect

22
go.sum
View file

@ -112,8 +112,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0=
github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 h1:vU+EP9ZuFUCYE0NYLwTSob+3LNEJATzNfP/DC7SWGWI=
github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs=
@ -131,12 +131,10 @@ github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/docker/cli v24.0.0+incompatible h1:0+1VshNwBQzQAx9lOl+OYCTCEAD8fKs/qeXMx3O0wqM=
github.com/docker/cli v24.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2oNn0GkeZE=
github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0=
github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
@ -148,8 +146,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I=
github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s=
github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.5.4 h1:TGU4tSjD3sCL788vFNeJnTdzpNKIw1H5dgLnJRQVv/k=
@ -201,8 +199,8 @@ github.com/google/certificate-transparency-go v1.2.1 h1:4iW/NwzqOqYEEoCBEFP+jPbB
github.com/google/certificate-transparency-go v1.2.1/go.mod h1:bvn/ytAccv+I6+DGkqpvSsEdiVGramgaSC6RD3tEmeE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-containerregistry v0.20.0 h1:wRqHpOeVh3DnenOrPy9xDOLdnLatiGuuNRVelR2gSbg=
github.com/google/go-containerregistry v0.20.0/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
github.com/google/go-containerregistry v0.20.2 h1:B1wPJ1SN/S7pB+ZAimcciVD+r+yV/l/DSArMxlbwseo=
github.com/google/go-containerregistry v0.20.2/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
@ -495,8 +493,8 @@ golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

View file

@ -198,6 +198,15 @@ func manPrintJSONFields(buf *bytes.Buffer, command *cobra.Command) {
buf.WriteString("\n")
}
func manPrintExitCodes(buf *bytes.Buffer) {
buf.WriteString("# EXIT CODES\n")
buf.WriteString("0: Successful execution\n\n")
buf.WriteString("1: Error\n\n")
buf.WriteString("2: Command canceled\n\n")
buf.WriteString("4: Authentication required\n\n")
buf.WriteString("NOTE: Specific commands may have additional exit codes. Refer to the command's help for more information.\n\n")
}
func genMan(cmd *cobra.Command, header *GenManHeader) []byte {
cmd.InitDefaultHelpCmd()
cmd.InitDefaultHelpFlag()
@ -217,6 +226,7 @@ func genMan(cmd *cobra.Command, header *GenManHeader) []byte {
manPrintOptions(buf, cmd)
manPrintAliases(buf, cmd)
manPrintJSONFields(buf, cmd)
manPrintExitCodes(buf)
if len(cmd.Example) > 0 {
buf.WriteString("# EXAMPLE\n")
buf.WriteString(fmt.Sprintf("```\n%s\n```\n", cmd.Example))

View file

@ -129,6 +129,31 @@ func TestGenManJSONFields(t *testing.T) {
checkStringContains(t, output, "baz")
}
func TestGenManDocExitCodes(t *testing.T) {
header := &GenManHeader{
Title: "Project",
Section: "1",
}
cmd := &cobra.Command{
Use: "test-command",
Short: "A test command",
Long: "A test command for checking exit codes section",
}
buf := new(bytes.Buffer)
if err := renderMan(cmd, header, buf); err != nil {
t.Fatal(err)
}
output := buf.String()
// Check for the presence of the exit codes section
checkStringContains(t, output, ".SH EXIT CODES")
checkStringContains(t, output, "0: Successful execution")
checkStringContains(t, output, "1: Error")
checkStringContains(t, output, "2: Command canceled")
checkStringContains(t, output, "4: Authentication required")
checkStringContains(t, output, "NOTE: Specific commands may have additional exit codes. Refer to the command's help for more information.")
}
func TestManPrintFlagsHidesShortDeprecated(t *testing.T) {
c := &cobra.Command{}
c.Flags().StringP("foo", "f", "default", "Foo flag")

View file

@ -62,14 +62,14 @@ func TestGetByDigest(t *testing.T) {
require.Equal(t, 5, len(attestations))
bundle := (attestations)[0].Bundle
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle+json;version=0.1")
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle.v0.3+json")
attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, DefaultLimit)
require.NoError(t, err)
require.Equal(t, 5, len(attestations))
bundle = (attestations)[0].Bundle
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle+json;version=0.1")
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle.v0.3+json")
}
func TestGetByDigestGreaterThanLimit(t *testing.T) {
@ -82,14 +82,14 @@ func TestGetByDigestGreaterThanLimit(t *testing.T) {
require.Equal(t, 3, len(attestations))
bundle := (attestations)[0].Bundle
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle+json;version=0.1")
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle.v0.3+json")
attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, limit)
require.NoError(t, err)
require.Equal(t, len(attestations), limit)
bundle = (attestations)[0].Bundle
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle+json;version=0.1")
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle.v0.3+json")
}
func TestGetByDigestWithNextPage(t *testing.T) {
@ -99,14 +99,14 @@ func TestGetByDigestWithNextPage(t *testing.T) {
require.Equal(t, len(attestations), 10)
bundle := (attestations)[0].Bundle
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle+json;version=0.1")
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle.v0.3+json")
attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, DefaultLimit)
require.NoError(t, err)
require.Equal(t, len(attestations), 10)
bundle = (attestations)[0].Bundle
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle+json;version=0.1")
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle.v0.3+json")
}
func TestGetByDigestGreaterThanLimitWithNextPage(t *testing.T) {
@ -119,14 +119,14 @@ func TestGetByDigestGreaterThanLimitWithNextPage(t *testing.T) {
require.Equal(t, len(attestations), limit)
bundle := (attestations)[0].Bundle
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle+json;version=0.1")
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle.v0.3+json")
attestations, err = c.GetByOwnerAndDigest(testOwner, testDigest, limit)
require.NoError(t, err)
require.Equal(t, len(attestations), limit)
bundle = (attestations)[0].Bundle
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle+json;version=0.1")
require.Equal(t, bundle.GetMediaType(), "application/vnd.dev.sigstore.bundle.v0.3+json")
}
func TestGetByDigest_NoAttestationsFound(t *testing.T) {

View file

@ -18,7 +18,7 @@ func NewCmdAttestation(f *cmdutil.Factory) *cobra.Command {
Aliases: []string{"at"},
Long: heredoc.Doc(`
Download and verify artifact attestations.
`),
`),
}
root.AddCommand(download.NewDownloadCmd(f, nil))

View file

@ -1 +1 @@
{"mediaType":"application/vnd.dev.sigstore.bundle+json;version=0.2","verificationMaterial":{"publicKey":{},"timestampVerificationData":{"rfc3161Timestamps":[{"signedTimestamp":"MIIC0jADAgEAMIICyQYJKoZIhvcNAQcCoIICujCCArYCAQMxDTALBglghkgBZQMEAgIwgbwGCyqGSIb3DQEJEAEEoIGsBIGpMIGmAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQgGIbhbjwKQeOttAHpYr4ZdztGymTk4PPmJo1M4wwN9s8CFQDfGDV1B9hFrCLmzlcmvopZMaQOpxgPMjAyNDA0MjIxNzMzMjZaMAMCAQGgNqQ0MDIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEZMBcGA1UEAxMQVFNBIFRpbWVzdGFtcGluZ6AAMYIB3zCCAdsCAQEwSjAyMRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xGTAXBgNVBAMTEFRTQSBpbnRlcm1lZGlhdGUCFDQ1ZZrWbr6Lo5+CsIgv6MSK/IcQMAsGCWCGSAFlAwQCAqCCAQUwGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNDA0MjIxNzMzMjZaMD8GCSqGSIb3DQEJBDEyBDAGSn57m09Ro452Mj6xp7ld68UOS58CRbsUAX0K7Oesj8Kcpo2xKRMwapTRYFWZF84wgYcGCyqGSIb3DQEJEAIvMXgwdjB0MHIEIC4X67ezV4q0OFecnkRUAx6sVRjb/Q6nZYy0cfMfHKgBME4wNqQ0MDIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEZMBcGA1UEAxMQVFNBIGludGVybWVkaWF0ZQIUNDVlmtZuvoujn4KwiC/oxIr8hxAwCgYIKoZIzj0EAwMEaDBmAjEA0DIXC6giK74kBGL9WRcy99QAvkKWM2N20fNLFxTVrPglT0oNrTzTiyVQgIN6w1/gAjEAqxEuJp/bRj/ADIHoCBp2+K+zI2opxLbD4rj3jLaezHnoNOYpLwP3lIwFDhYU1a8a"}]}}}
{"mediaType":"application/vnd.dev.sigstore.bundle.v0.3+json","verificationMaterial":{"publicKey":{},"timestampVerificationData":{"rfc3161Timestamps":[{"signedTimestamp":"MIIC0jADAgEAMIICyQYJKoZIhvcNAQcCoIICujCCArYCAQMxDTALBglghkgBZQMEAgIwgbwGCyqGSIb3DQEJEAEEoIGsBIGpMIGmAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQgGIbhbjwKQeOttAHpYr4ZdztGymTk4PPmJo1M4wwN9s8CFQDfGDV1B9hFrCLmzlcmvopZMaQOpxgPMjAyNDA0MjIxNzMzMjZaMAMCAQGgNqQ0MDIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEZMBcGA1UEAxMQVFNBIFRpbWVzdGFtcGluZ6AAMYIB3zCCAdsCAQEwSjAyMRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xGTAXBgNVBAMTEFRTQSBpbnRlcm1lZGlhdGUCFDQ1ZZrWbr6Lo5+CsIgv6MSK/IcQMAsGCWCGSAFlAwQCAqCCAQUwGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNDA0MjIxNzMzMjZaMD8GCSqGSIb3DQEJBDEyBDAGSn57m09Ro452Mj6xp7ld68UOS58CRbsUAX0K7Oesj8Kcpo2xKRMwapTRYFWZF84wgYcGCyqGSIb3DQEJEAIvMXgwdjB0MHIEIC4X67ezV4q0OFecnkRUAx6sVRjb/Q6nZYy0cfMfHKgBME4wNqQ0MDIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEZMBcGA1UEAxMQVFNBIGludGVybWVkaWF0ZQIUNDVlmtZuvoujn4KwiC/oxIr8hxAwCgYIKoZIzj0EAwMEaDBmAjEA0DIXC6giK74kBGL9WRcy99QAvkKWM2N20fNLFxTVrPglT0oNrTzTiyVQgIN6w1/gAjEAqxEuJp/bRj/ADIHoCBp2+K+zI2opxLbD4rj3jLaezHnoNOYpLwP3lIwFDhYU1a8a"}]}}}

View file

@ -1 +1 @@
{"mediaType":"application/vnd.dev.sigstore.bundle+json;version=0.2","dsseEnvelope":{"payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoiZ2l0aHViX3Byb3ZlbmFuY2VfZGVtby0wLjAuMTItcHkzLW5vbmUtYW55LndobCIsImRpZ2VzdCI6eyJzaGEyNTYiOiJhZTU3OTM2ZGVmNTliYzRjNzVlZGQzYTgzN2Q4OWJjZWZjNmQzYTVlMzFkNTVhNmZhN2E3MTYyNGY5MmMzYzNiIn19XSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vc2xzYS5kZXYvcHJvdmVuYW5jZS92MSIsInByZWRpY2F0ZSI6eyJidWlsZERlZmluaXRpb24iOnsiYnVpbGRUeXBlIjoiaHR0cHM6Ly9zbHNhLWZyYW1ld29yay5naXRodWIuaW8vZ2l0aHViLWFjdGlvbnMtYnVpbGR0eXBlcy93b3JrZmxvdy92MSIsImV4dGVybmFsUGFyYW1ldGVycyI6eyJ3b3JrZmxvdyI6eyJyZWYiOiJyZWZzL2hlYWRzL21haW4iLCJyZXBvc2l0b3J5IjoiaHR0cHM6Ly9naXRodWIuY29tL2FjdGlvbnMvYXR0ZXN0LWRlbW8iLCJwYXRoIjoiLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQtcHl0aG9uLnltbCJ9fSwiaW50ZXJuYWxQYXJhbWV0ZXJzIjp7ImdpdGh1YiI6eyJldmVudF9uYW1lIjoid29ya2Zsb3dfZGlzcGF0Y2giLCJyZXBvc2l0b3J5X2lkIjoiNzYzMjg3NTMyIiwicmVwb3NpdG9yeV9vd25lcl9pZCI6IjQ0MDM2NTYyIn19LCJyZXNvbHZlZERlcGVuZGVuY2llcyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL2F0dGVzdC1kZW1vQHJlZnMvaGVhZHMvbWFpbiIsImRpZ2VzdCI6eyJnaXRDb21taXQiOiJhNmMyM2I5ODA2YzU5MzY2NGY2ODYzN2M4ZjlkNDVkZmNmOThiMmRiIn19XX0sInJ1bkRldGFpbHMiOnsiYnVpbGRlciI6eyJpZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL3J1bm5lci9naXRodWItaG9zdGVkIn0sIm1ldGFkYXRhIjp7Imludm9jYXRpb25JZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL2F0dGVzdC1kZW1vL2FjdGlvbnMvcnVucy84Nzg4Mzg5NjAxL2F0dGVtcHRzLzEifX19fQ==","payloadType":"application/vnd.in-toto+json","signatures":[{"sig":"MEUCIAgJYzFW0xtAGqTzSn8UWxvT16QLL1qLolcylZsN39U/AiEA/HSUE5sCPEkEHuZgsPS7LkZ9SkMlHGHhpMU3RsV/cYw="}]}}
{"mediaType":"application/vnd.dev.sigstore.bundle+json;version=0.3","dsseEnvelope":{"payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoiZ2l0aHViX3Byb3ZlbmFuY2VfZGVtby0wLjAuMTItcHkzLW5vbmUtYW55LndobCIsImRpZ2VzdCI6eyJzaGEyNTYiOiJhZTU3OTM2ZGVmNTliYzRjNzVlZGQzYTgzN2Q4OWJjZWZjNmQzYTVlMzFkNTVhNmZhN2E3MTYyNGY5MmMzYzNiIn19XSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vc2xzYS5kZXYvcHJvdmVuYW5jZS92MSIsInByZWRpY2F0ZSI6eyJidWlsZERlZmluaXRpb24iOnsiYnVpbGRUeXBlIjoiaHR0cHM6Ly9zbHNhLWZyYW1ld29yay5naXRodWIuaW8vZ2l0aHViLWFjdGlvbnMtYnVpbGR0eXBlcy93b3JrZmxvdy92MSIsImV4dGVybmFsUGFyYW1ldGVycyI6eyJ3b3JrZmxvdyI6eyJyZWYiOiJyZWZzL2hlYWRzL21haW4iLCJyZXBvc2l0b3J5IjoiaHR0cHM6Ly9naXRodWIuY29tL2FjdGlvbnMvYXR0ZXN0LWRlbW8iLCJwYXRoIjoiLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQtcHl0aG9uLnltbCJ9fSwiaW50ZXJuYWxQYXJhbWV0ZXJzIjp7ImdpdGh1YiI6eyJldmVudF9uYW1lIjoid29ya2Zsb3dfZGlzcGF0Y2giLCJyZXBvc2l0b3J5X2lkIjoiNzYzMjg3NTMyIiwicmVwb3NpdG9yeV9vd25lcl9pZCI6IjQ0MDM2NTYyIn19LCJyZXNvbHZlZERlcGVuZGVuY2llcyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL2F0dGVzdC1kZW1vQHJlZnMvaGVhZHMvbWFpbiIsImRpZ2VzdCI6eyJnaXRDb21taXQiOiJhNmMyM2I5ODA2YzU5MzY2NGY2ODYzN2M4ZjlkNDVkZmNmOThiMmRiIn19XX0sInJ1bkRldGFpbHMiOnsiYnVpbGRlciI6eyJpZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL3J1bm5lci9naXRodWItaG9zdGVkIn0sIm1ldGFkYXRhIjp7Imludm9jYXRpb25JZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL2F0dGVzdC1kZW1vL2FjdGlvbnMvcnVucy84Nzg4Mzg5NjAxL2F0dGVtcHRzLzEifX19fQ==","payloadType":"application/vnd.in-toto+json","signatures":[{"sig":"MEUCIAgJYzFW0xtAGqTzSn8UWxvT16QLL1qLolcylZsN39U/AiEA/HSUE5sCPEkEHuZgsPS7LkZ9SkMlHGHhpMU3RsV/cYw="}]}}

View file

@ -1 +1 @@
{"mediaType":"application/vnd.dev.sigstore.bundle+json;version=0.2","verificationMaterial":{"x509CertificateChain":{"certificates":[{"rawBytes":"MIIGZjCCBeygAwIBAgIUZCNUZ8MMbrK0CrXtb6QFhFMAA6wwCgYIKoZIzj0EAwMwODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZGdWxjaW8gSW50ZXJtZWRpYXRlIGwyMB4XDTI0MDQyMjE3MzMyNloXDTI0MDQyMjE3NDMyNlowADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLq8PHWv71CECMctIxOYXeUm893MJEazyiLqAJPmEHx8oJsk+vYt8zvEjfL6OAiUpR60Cfk5moqCrr4WwvM3jPujggUKMIIFBjAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYDVR0OBBYEFK10jC8CJcrMLDA80Jf4joCWq+H5MB8GA1UdIwQYMBaAFJtL5A5EGdvYbrWHWsiaGyEZn/4jMGcGA1UdEQEB/wRdMFuGWWh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL2F0dGVzdC1kZW1vLy5naXRodWIvd29ya2Zsb3dzL2J1aWxkLXB5dGhvbi55bWxAcmVmcy9oZWFkcy9tYWluMDkGCisGAQQBg78wAQEEK2h0dHBzOi8vdG9rZW4uYWN0aW9ucy5naXRodWJ1c2VyY29udGVudC5jb20wHwYKKwYBBAGDvzABAgQRd29ya2Zsb3dfZGlzcGF0Y2gwNgYKKwYBBAGDvzABAwQoYTZjMjNiOTgwNmM1OTM2NjRmNjg2MzdjOGY5ZDQ1ZGZjZjk4YjJkYjAvBgorBgEEAYO/MAEEBCFCdWlsZCBwYWNrYWdlIGFuZCBwdWJsaXNoIHRvIFB5UEkwIQYKKwYBBAGDvzABBQQTYWN0aW9ucy9hdHRlc3QtZGVtbzAdBgorBgEEAYO/MAEGBA9yZWZzL2hlYWRzL21haW4wOwYKKwYBBAGDvzABCAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tMGkGCisGAQQBg78wAQkEWwxZaHR0cHM6Ly9naXRodWIuY29tL2FjdGlvbnMvYXR0ZXN0LWRlbW8vLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQtcHl0aG9uLnltbEByZWZzL2hlYWRzL21haW4wOAYKKwYBBAGDvzABCgQqDChhNmMyM2I5ODA2YzU5MzY2NGY2ODYzN2M4ZjlkNDVkZmNmOThiMmRiMB0GCisGAQQBg78wAQsEDwwNZ2l0aHViLWhvc3RlZDA2BgorBgEEAYO/MAEMBCgMJmh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL2F0dGVzdC1kZW1vMDgGCisGAQQBg78wAQ0EKgwoYTZjMjNiOTgwNmM1OTM2NjRmNjg2MzdjOGY5ZDQ1ZGZjZjk4YjJkYjAfBgorBgEEAYO/MAEOBBEMD3JlZnMvaGVhZHMvbWFpbjAZBgorBgEEAYO/MAEPBAsMCTc2MzI4NzUzMjAqBgorBgEEAYO/MAEQBBwMGmh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zMBgGCisGAQQBg78wAREECgwINDQwMzY1NjIwaQYKKwYBBAGDvzABEgRbDFlodHRwczovL2dpdGh1Yi5jb20vYWN0aW9ucy9hdHRlc3QtZGVtby8uZ2l0aHViL3dvcmtmbG93cy9idWlsZC1weXRob24ueW1sQHJlZnMvaGVhZHMvbWFpbjA4BgorBgEEAYO/MAETBCoMKGE2YzIzYjk4MDZjNTkzNjY0ZjY4NjM3YzhmOWQ0NWRmY2Y5OGIyZGIwIQYKKwYBBAGDvzABFAQTDBF3b3JrZmxvd19kaXNwYXRjaDBZBgorBgEEAYO/MAEVBEsMSWh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL2F0dGVzdC1kZW1vL2FjdGlvbnMvcnVucy84Nzg4Mzg5NjAxL2F0dGVtcHRzLzEwFwYKKwYBBAGDvzABFgQJDAdwcml2YXRlMAoGCCqGSM49BAMDA2gAMGUCME4MEsuiTVolcvctwKJn7TEfi9mIXxhfBRcV0Nox1UPvdc4EyO/gjYPqfWVbqi74CgIxANLkoV0aAeOaIuA1srkA1uIGmhuA820pXs0kbqW06cNuJie4+3B4PydoYoJjy1BZCQ=="}]},"timestampVerificationData":{"rfc3161Timestamps":[{"signedTimestamp":"MIIC0jADAgEAMIICyQYJKoZIhvcNAQcCoIICujCCArYCAQMxDTALBglghkgBZQMEAgIwgbwGCyqGSIb3DQEJEAEEoIGsBIGpMIGmAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQgGIbhbjwKQeOttAHpYr4ZdztGymTk4PPmJo1M4wwN9s8CFQDfGDV1B9hFrCLmzlcmvopZMaQOpxgPMjAyNDA0MjIxNzMzMjZaMAMCAQGgNqQ0MDIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEZMBcGA1UEAxMQVFNBIFRpbWVzdGFtcGluZ6AAMYIB3zCCAdsCAQEwSjAyMRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xGTAXBgNVBAMTEFRTQSBpbnRlcm1lZGlhdGUCFDQ1ZZrWbr6Lo5+CsIgv6MSK/IcQMAsGCWCGSAFlAwQCAqCCAQUwGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNDA0MjIxNzMzMjZaMD8GCSqGSIb3DQEJBDEyBDAGSn57m09Ro452Mj6xp7ld68UOS58CRbsUAX0K7Oesj8Kcpo2xKRMwapTRYFWZF84wgYcGCyqGSIb3DQEJEAIvMXgwdjB0MHIEIC4X67ezV4q0OFecnkRUAx6sVRjb/Q6nZYy0cfMfHKgBME4wNqQ0MDIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEZMBcGA1UEAxMQVFNBIGludGVybWVkaWF0ZQIUNDVlmtZuvoujn4KwiC/oxIr8hxAwCgYIKoZIzj0EAwMEaDBmAjEA0DIXC6giK74kBGL9WRcy99QAvkKWM2N20fNLFxTVrPglT0oNrTzTiyVQgIN6w1/gAjEAqxEuJp/bRj/ADIHoCBp2+K+zI2opxLbD4rj3jLaezHnoNOYpLwP3lIwFDhYU1a8a"}]}},"dsseEnvelope":{"payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoiZ2l0aHViX3Byb3ZlbmFuY2VfZGVtby0wLjAuMTItcHkzLW5vbmUtYW55LndobCIsImRpZ2VzdCI6eyJzaGEyNTYiOiJhZTU3OTM2ZGVmNTliYzRjNzVlZGQzYTgzN2Q4OWJjZWZjNmQzYTVlMzFkNTVhNmZhN2E3MTYyNGY5MmMzYzNiIn19XSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vc2xzYS5kZXYvcHJvdmVuYW5jZS92MSIsInByZWRpY2F0ZSI6eyJidWlsZERlZmluaXRpb24iOnsiYnVpbGRUeXBlIjoiaHR0cHM6Ly9zbHNhLWZyYW1ld29yay5naXRodWIuaW8vZ2l0aHViLWFjdGlvbnMtYnVpbGR0eXBlcy93b3JrZmxvdy92MSIsImV4dGVybmFsUGFyYW1ldGVycyI6eyJ3b3JrZmxvdyI6eyJyZWYiOiJyZWZzL2hlYWRzL21haW4iLCJyZXBvc2l0b3J5IjoiaHR0cHM6Ly9naXRodWIuY29tL2FjdGlvbnMvYXR0ZXN0LWRlbW8iLCJwYXRoIjoiLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQtcHl0aG9uLnltbCJ9fSwiaW50ZXJuYWxQYXJhbWV0ZXJzIjp7ImdpdGh1YiI6eyJldmVudF9uYW1lIjoid29ya2Zsb3dfZGlzcGF0Y2giLCJyZXBvc2l0b3J5X2lkIjoiNzYzMjg3NTMyIiwicmVwb3NpdG9yeV9vd25lcl9pZCI6IjQ0MDM2NTYyIn19LCJyZXNvbHZlZERlcGVuZGVuY2llcyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL2F0dGVzdC1kZW1vQHJlZnMvaGVhZHMvbWFpbiIsImRpZ2VzdCI6eyJnaXRDb21taXQiOiJhNmMyM2I5ODA2YzU5MzY2NGY2ODYzN2M4ZjlkNDVkZmNmOThiMmRiIn19XX0sInJ1bkRldGFpbHMiOnsiYnVpbGRlciI6eyJpZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL3J1bm5lci9naXRodWItaG9zdGVkIn0sIm1ldGFkYXRhIjp7Imludm9jYXRpb25JZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL2F0dGVzdC1kZW1vL2FjdGlvbnMvcnVucy84Nzg4Mzg5NjAxL2F0dGVtcHRzLzEifX19fQ==","payloadType":"application/vnd.in-toto+json","signatures":[{"sig":"MEUCIAgJYzFW0xtAGqTzSn8UWxvT16QLL1qLolcylZsN39U/AiEA/HSUE5sCPEkEHuZgsPS7LkZ9SkMlHGHhpMU3RsV/cYw="}]}}
{"mediaType":"application/vnd.dev.sigstore.bundle.v0.3+json","verificationMaterial":{"certificate":{"rawBytes":"MIIGZjCCBeygAwIBAgIUZCNUZ8MMbrK0CrXtb6QFhFMAA6wwCgYIKoZIzj0EAwMwODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZGdWxjaW8gSW50ZXJtZWRpYXRlIGwyMB4XDTI0MDQyMjE3MzMyNloXDTI0MDQyMjE3NDMyNlowADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLq8PHWv71CECMctIxOYXeUm893MJEazyiLqAJPmEHx8oJsk+vYt8zvEjfL6OAiUpR60Cfk5moqCrr4WwvM3jPujggUKMIIFBjAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYDVR0OBBYEFK10jC8CJcrMLDA80Jf4joCWq+H5MB8GA1UdIwQYMBaAFJtL5A5EGdvYbrWHWsiaGyEZn/4jMGcGA1UdEQEB/wRdMFuGWWh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL2F0dGVzdC1kZW1vLy5naXRodWIvd29ya2Zsb3dzL2J1aWxkLXB5dGhvbi55bWxAcmVmcy9oZWFkcy9tYWluMDkGCisGAQQBg78wAQEEK2h0dHBzOi8vdG9rZW4uYWN0aW9ucy5naXRodWJ1c2VyY29udGVudC5jb20wHwYKKwYBBAGDvzABAgQRd29ya2Zsb3dfZGlzcGF0Y2gwNgYKKwYBBAGDvzABAwQoYTZjMjNiOTgwNmM1OTM2NjRmNjg2MzdjOGY5ZDQ1ZGZjZjk4YjJkYjAvBgorBgEEAYO/MAEEBCFCdWlsZCBwYWNrYWdlIGFuZCBwdWJsaXNoIHRvIFB5UEkwIQYKKwYBBAGDvzABBQQTYWN0aW9ucy9hdHRlc3QtZGVtbzAdBgorBgEEAYO/MAEGBA9yZWZzL2hlYWRzL21haW4wOwYKKwYBBAGDvzABCAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tMGkGCisGAQQBg78wAQkEWwxZaHR0cHM6Ly9naXRodWIuY29tL2FjdGlvbnMvYXR0ZXN0LWRlbW8vLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQtcHl0aG9uLnltbEByZWZzL2hlYWRzL21haW4wOAYKKwYBBAGDvzABCgQqDChhNmMyM2I5ODA2YzU5MzY2NGY2ODYzN2M4ZjlkNDVkZmNmOThiMmRiMB0GCisGAQQBg78wAQsEDwwNZ2l0aHViLWhvc3RlZDA2BgorBgEEAYO/MAEMBCgMJmh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL2F0dGVzdC1kZW1vMDgGCisGAQQBg78wAQ0EKgwoYTZjMjNiOTgwNmM1OTM2NjRmNjg2MzdjOGY5ZDQ1ZGZjZjk4YjJkYjAfBgorBgEEAYO/MAEOBBEMD3JlZnMvaGVhZHMvbWFpbjAZBgorBgEEAYO/MAEPBAsMCTc2MzI4NzUzMjAqBgorBgEEAYO/MAEQBBwMGmh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zMBgGCisGAQQBg78wAREECgwINDQwMzY1NjIwaQYKKwYBBAGDvzABEgRbDFlodHRwczovL2dpdGh1Yi5jb20vYWN0aW9ucy9hdHRlc3QtZGVtby8uZ2l0aHViL3dvcmtmbG93cy9idWlsZC1weXRob24ueW1sQHJlZnMvaGVhZHMvbWFpbjA4BgorBgEEAYO/MAETBCoMKGE2YzIzYjk4MDZjNTkzNjY0ZjY4NjM3YzhmOWQ0NWRmY2Y5OGIyZGIwIQYKKwYBBAGDvzABFAQTDBF3b3JrZmxvd19kaXNwYXRjaDBZBgorBgEEAYO/MAEVBEsMSWh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL2F0dGVzdC1kZW1vL2FjdGlvbnMvcnVucy84Nzg4Mzg5NjAxL2F0dGVtcHRzLzEwFwYKKwYBBAGDvzABFgQJDAdwcml2YXRlMAoGCCqGSM49BAMDA2gAMGUCME4MEsuiTVolcvctwKJn7TEfi9mIXxhfBRcV0Nox1UPvdc4EyO/gjYPqfWVbqi74CgIxANLkoV0aAeOaIuA1srkA1uIGmhuA820pXs0kbqW06cNuJie4+3B4PydoYoJjy1BZCQ=="},"timestampVerificationData":{"rfc3161Timestamps":[{"signedTimestamp":"MIIC0jADAgEAMIICyQYJKoZIhvcNAQcCoIICujCCArYCAQMxDTALBglghkgBZQMEAgIwgbwGCyqGSIb3DQEJEAEEoIGsBIGpMIGmAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQgGIbhbjwKQeOttAHpYr4ZdztGymTk4PPmJo1M4wwN9s8CFQDfGDV1B9hFrCLmzlcmvopZMaQOpxgPMjAyNDA0MjIxNzMzMjZaMAMCAQGgNqQ0MDIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEZMBcGA1UEAxMQVFNBIFRpbWVzdGFtcGluZ6AAMYIB3zCCAdsCAQEwSjAyMRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xGTAXBgNVBAMTEFRTQSBpbnRlcm1lZGlhdGUCFDQ1ZZrWbr6Lo5+CsIgv6MSK/IcQMAsGCWCGSAFlAwQCAqCCAQUwGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNDA0MjIxNzMzMjZaMD8GCSqGSIb3DQEJBDEyBDAGSn57m09Ro452Mj6xp7ld68UOS58CRbsUAX0K7Oesj8Kcpo2xKRMwapTRYFWZF84wgYcGCyqGSIb3DQEJEAIvMXgwdjB0MHIEIC4X67ezV4q0OFecnkRUAx6sVRjb/Q6nZYy0cfMfHKgBME4wNqQ0MDIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEZMBcGA1UEAxMQVFNBIGludGVybWVkaWF0ZQIUNDVlmtZuvoujn4KwiC/oxIr8hxAwCgYIKoZIzj0EAwMEaDBmAjEA0DIXC6giK74kBGL9WRcy99QAvkKWM2N20fNLFxTVrPglT0oNrTzTiyVQgIN6w1/gAjEAqxEuJp/bRj/ADIHoCBp2+K+zI2opxLbD4rj3jLaezHnoNOYpLwP3lIwFDhYU1a8a"}]}},"dsseEnvelope":{"payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoiZ2l0aHViX3Byb3ZlbmFuY2VfZGVtby0wLjAuMTItcHkzLW5vbmUtYW55LndobCIsImRpZ2VzdCI6eyJzaGEyNTYiOiJhZTU3OTM2ZGVmNTliYzRjNzVlZGQzYTgzN2Q4OWJjZWZjNmQzYTVlMzFkNTVhNmZhN2E3MTYyNGY5MmMzYzNiIn19XSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vc2xzYS5kZXYvcHJvdmVuYW5jZS92MSIsInByZWRpY2F0ZSI6eyJidWlsZERlZmluaXRpb24iOnsiYnVpbGRUeXBlIjoiaHR0cHM6Ly9zbHNhLWZyYW1ld29yay5naXRodWIuaW8vZ2l0aHViLWFjdGlvbnMtYnVpbGR0eXBlcy93b3JrZmxvdy92MSIsImV4dGVybmFsUGFyYW1ldGVycyI6eyJ3b3JrZmxvdyI6eyJyZWYiOiJyZWZzL2hlYWRzL21haW4iLCJyZXBvc2l0b3J5IjoiaHR0cHM6Ly9naXRodWIuY29tL2FjdGlvbnMvYXR0ZXN0LWRlbW8iLCJwYXRoIjoiLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQtcHl0aG9uLnltbCJ9fSwiaW50ZXJuYWxQYXJhbWV0ZXJzIjp7ImdpdGh1YiI6eyJldmVudF9uYW1lIjoid29ya2Zsb3dfZGlzcGF0Y2giLCJyZXBvc2l0b3J5X2lkIjoiNzYzMjg3NTMyIiwicmVwb3NpdG9yeV9vd25lcl9pZCI6IjQ0MDM2NTYyIn19LCJyZXNvbHZlZERlcGVuZGVuY2llcyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL2F0dGVzdC1kZW1vQHJlZnMvaGVhZHMvbWFpbiIsImRpZ2VzdCI6eyJnaXRDb21taXQiOiJhNmMyM2I5ODA2YzU5MzY2NGY2ODYzN2M4ZjlkNDVkZmNmOThiMmRiIn19XX0sInJ1bkRldGFpbHMiOnsiYnVpbGRlciI6eyJpZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL3J1bm5lci9naXRodWItaG9zdGVkIn0sIm1ldGFkYXRhIjp7Imludm9jYXRpb25JZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL2F0dGVzdC1kZW1vL2FjdGlvbnMvcnVucy84Nzg4Mzg5NjAxL2F0dGVtcHRzLzEifX19fQ==","payloadType":"application/vnd.in-toto+json","signatures":[{"sig":"MEUCIAgJYzFW0xtAGqTzSn8UWxvT16QLL1qLolcylZsN39U/AiEA/HSUE5sCPEkEHuZgsPS7LkZ9SkMlHGHhpMU3RsV/cYw="}]}}

View file

@ -0,0 +1,61 @@
{
"mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.1",
"verificationMaterial": {
"x509CertificateChain": {
"certificates": [
{
"rawBytes": "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"
}
]
},
"tlogEntries": [
{
"logIndex": "33351527",
"logId": {
"keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="
},
"kindVersion": {
"kind": "intoto",
"version": "0.0.2"
},
"integratedTime": "1693323623",
"inclusionPromise": {
"signedEntryTimestamp": "MEYCIQDhWvNSLvnq5ZS3qTIgC7K2uQFeA0g8FEEjNo1UQxeubAIhALDrD1uIiUkk3tQNp/4gKT/9j8zEyyxi9Ti+qaD8q2vI"
},
"inclusionProof": {
"logIndex": "29188096",
"rootHash": "fbEijQTFeiQCldZqez/u/WcrNPk4nxXI5ihofHYjFUA=",
"treeSize": "29188099",
"hashes": [
"z7VKeAC2d2x18Vtxt7n40GS3gtc1xfRwjjxxzpy/Trw=",
"/Kd8ZuCLZ7MukSwpjaSgxKFl5X2vdHWk6/qpNrkiUJo=",
"vvkKs7IShUI15nVb9c5olPgBnL9r4uP7+d5KzV0hSjs=",
"Fg4p0WJZw8Lghrpxkx1SXgzfroTeIIrEgEbfgr9IdXY=",
"bH8NahqE+hQ58Qxhg0V5fYusFQ1xsaQ/rK6slWVRT5k=",
"HplNgZ3/afEHq52zcfL2s1AKisOYDdMCWK1jOu1tGyw=",
"uOPuC2YDmwZe989ZN3Lgh5CKMXh9HETrSNgf0jV0WkM=",
"eVsvWKnEZ1+Xo3Ba15DfEiIhhmlrEaIeb+VfYmx8KhY=",
"uLuBRins5nkqq2rqd17R27pQTUF+xetttC6MsmlUzd0=",
"jRUq4D8O+FI47Wbw96s7yHCu4qzWUxpIVfxQEeprDmc=",
"rXEsmEJN4PEoTU8US4qVtdIsGB1MCiRlGOepoiC99kM="
],
"checkpoint": {
"envelope": "rekor.sigstore.dev - 2605736670972794746\n29188099\nfbEijQTFeiQCldZqez/u/WcrNPk4nxXI5ihofHYjFUA=\nTimestamp: 1693323623528968756\n\n— rekor.sigstore.dev wNI9ajBEAiAK0YTbxRlhOZeeP+844Y+W7iz+hsFIF8x2NYsmuaxifAIgYUFSurlKwN7j5jCwpqSVrkbouQoYIYlyWU9Om16svmI=\n"
}
},
"canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjIiLCJraW5kIjoiaW50b3RvIiwic3BlYyI6eyJjb250ZW50Ijp7ImVudmVsb3BlIjp7InBheWxvYWRUeXBlIjoiYXBwbGljYXRpb24vdm5kLmluLXRvdG8ranNvbiIsInNpZ25hdHVyZXMiOlt7InB1YmxpY0tleSI6IkxTMHRMUzFDUlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVWQwUkVORFFtcDFaMEYzU1VKQlowbFZRMHBNYVhCVGREQTVTMHhHWXpCS1dXWjFSSEpUWVc0dkwweHpkME5uV1VsTGIxcEplbW93UlVGM1RYY0tUbnBGVmsxQ1RVZEJNVlZGUTJoTlRXTXliRzVqTTFKMlkyMVZkVnBIVmpKTlVqUjNTRUZaUkZaUlVVUkZlRlo2WVZka2VtUkhPWGxhVXpGd1ltNVNiQXBqYlRGc1drZHNhR1JIVlhkSWFHTk9UV3BOZDA5RVNUVk5WRlV3VFVSSmVsZG9ZMDVOYWsxM1QwUkpOVTFVVlRGTlJFbDZWMnBCUVUxR2EzZEZkMWxJQ2t0dldrbDZhakJEUVZGWlNVdHZXa2w2YWpCRVFWRmpSRkZuUVVWUVptMDJURkJZVVdWS1ZFTTRPVlZQY1dsT1YyMXVXbGxIYlZnMFZETnBURnBIYVRBS1JWWTBZbVpQYjAwNE5raDZZVGswV0hGNWRYZDRRVzlYY0VOUVpXTkdRMFZpUVdVNGJESmtaeTlsY2pOUE9VeEZSbkZQUTBKV2IzZG5aMVpYVFVFMFJ3cEJNVlZrUkhkRlFpOTNVVVZCZDBsSVowUkJWRUpuVGxaSVUxVkZSRVJCUzBKblozSkNaMFZHUWxGalJFRjZRV1JDWjA1V1NGRTBSVVpuVVZWbGNYQkRDbGhJY2pOd1kxVmhURE5GUmt0U0swdHpiWFZMVVhGdmQwaDNXVVJXVWpCcVFrSm5kMFp2UVZVek9WQndlakZaYTBWYVlqVnhUbXB3UzBaWGFYaHBORmtLV2tRNGQxbDNXVVJXVWpCU1FWRklMMEpHYTNkV05GcFdZVWhTTUdOSVRUWk1lVGx1WVZoU2IyUlhTWFZaTWpsMFRETk9jRm96VGpCaU0wcHNURE5PY0FwYU0wNHdZak5LYkV4WGNIcE1lVFZ1WVZoU2IyUlhTWFprTWpsNVlUSmFjMkl6WkhwTU0wcHNZa2RXYUdNeVZYVmxWekZ6VVVoS2JGcHVUWFpoUjFab0NscElUWFppVjBad1ltcEJOVUpuYjNKQ1owVkZRVmxQTDAxQlJVSkNRM1J2WkVoU2QyTjZiM1pNTTFKMllUSldkVXh0Um1wa1IyeDJZbTVOZFZveWJEQUtZVWhXYVdSWVRteGpiVTUyWW01U2JHSnVVWFZaTWpsMFRVSkpSME5wYzBkQlVWRkNaemM0ZDBGUlNVVkNTRUl4WXpKbmQwNW5XVXRMZDFsQ1FrRkhSQXAyZWtGQ1FYZFJiMDFxV210TlZGa3hUVlJOZWs5RVdtMWFiVVpvVG5wcmQxbHFSbXBOZWtwdFQxUkpNMDVVVVRCYWFrVjZUV3BLYkU1RVJUVk9SRUZXQ2tKbmIzSkNaMFZGUVZsUEwwMUJSVVZDUVdSVFdsZDRiRmxZVG14TlEwbEhRMmx6UjBGUlVVSm5OemgzUVZGVlJVWklUbkJhTTA0d1lqTktiRXd6VG5BS1dqTk9NR0l6U214TVYzQjZUVUl3UjBOcGMwZEJVVkZDWnpjNGQwRlJXVVZFTTBwc1dtNU5kbUZIVm1oYVNFMTJZbGRHY0dKcVFUZENaMjl5UW1kRlJRcEJXVTh2VFVGRlNVSkRNRTFMTW1nd1pFaENlazlwT0haa1J6bHlXbGMwZFZsWFRqQmhWemwxWTNrMWJtRllVbTlrVjBveFl6SldlVmt5T1hWa1IxWjFDbVJETldwaU1qQjNXbEZaUzB0M1dVSkNRVWRFZG5wQlFrTlJVbGhFUmxadlpFaFNkMk42YjNaTU1tUndaRWRvTVZscE5XcGlNakIyWXpKc2JtTXpVbllLWTIxVmRtTXliRzVqTTFKMlkyMVZkR0Z1VFhaTWJXUndaRWRvTVZscE9UTmlNMHB5V20xNGRtUXpUWFpqYlZaeldsZEdlbHBUTlRWaVYzaEJZMjFXYlFwamVUbHZXbGRHYTJONU9YUlpWMngxVFVSblIwTnBjMGRCVVZGQ1p6YzRkMEZSYjBWTFozZHZUV3BhYTAxVVdURk5WRTE2VDBSYWJWcHRSbWhPZW10M0NsbHFSbXBOZWtwdFQxUkpNMDVVVVRCYWFrVjZUV3BLYkU1RVJUVk9SRUZrUW1kdmNrSm5SVVZCV1U4dlRVRkZURUpCT0UxRVYyUndaRWRvTVZscE1XOEtZak5PTUZwWFVYZE9kMWxMUzNkWlFrSkJSMFIyZWtGQ1JFRlJjRVJEWkc5a1NGSjNZM3B2ZGt3eVpIQmtSMmd4V1drMWFtSXlNSFpqTW14dVl6TlNkZ3BqYlZWMll6SnNibU16VW5aamJWVjBZVzVOZDA5QldVdExkMWxDUWtGSFJIWjZRVUpFVVZGeFJFTm5lVTV0VVhoT2FsVjRUWHBOTkU1dFdtMVpWMFV6Q2s5VVFtbE5WMDE2VFcxWk5VMXFZekZPUkZKdFRWUk5lVTF0VlRCTlZHc3dUVUk0UjBOcGMwZEJVVkZDWnpjNGQwRlJORVZGVVhkUVkyMVdiV041T1c4S1dsZEdhMk41T1hSWlYyeDFUVUpyUjBOcGMwZEJVVkZDWnpjNGQwRlJPRVZEZDNkS1RrUnJNVTVVWXpCT1ZGVXhUVU56UjBOcGMwZEJVVkZDWnpjNGR3cEJVa0ZGU0ZGM1ltRklVakJqU0UwMlRIazVibUZZVW05a1YwbDFXVEk1ZEV3elRuQmFNMDR3WWpOS2JFMUNaMGREYVhOSFFWRlJRbWMzT0hkQlVrVkZDa05uZDBsT2VrVjNUMVJaZWs1VVRYZGFVVmxMUzNkWlFrSkJSMFIyZWtGQ1JXZFNXRVJHVm05a1NGSjNZM3B2ZGt3eVpIQmtSMmd4V1drMWFtSXlNSFlLWXpKc2JtTXpVblpqYlZWMll6SnNibU16VW5aamJWVjBZVzVOZGt4dFpIQmtSMmd4V1drNU0ySXpTbkphYlhoMlpETk5kbU50Vm5OYVYwWjZXbE0xTlFwaVYzaEJZMjFXYldONU9XOWFWMFpyWTNrNWRGbFhiSFZOUkdkSFEybHpSMEZSVVVKbk56aDNRVkpOUlV0bmQyOU5hbHByVFZSWk1VMVVUWHBQUkZwdENscHRSbWhPZW10M1dXcEdhazE2U20xUFZFa3pUbFJSTUZwcVJYcE5ha3BzVGtSRk5VNUVRVlZDWjI5eVFtZEZSVUZaVHk5TlFVVlZRa0ZaVFVKSVFqRUtZekpuZDFkbldVdExkMWxDUWtGSFJIWjZRVUpHVVZKTlJFVndiMlJJVW5kamVtOTJUREprY0dSSGFERlphVFZxWWpJd2RtTXliRzVqTTFKMlkyMVZkZ3BqTW14dVl6TlNkbU50VlhSaGJrMTJXVmRPTUdGWE9YVmplVGw1WkZjMWVreDZXWGROVkZFd1QwUm5NazVxV1haWldGSXdXbGN4ZDJSSVRYWk5WRUZYQ2tKbmIzSkNaMFZGUVZsUEwwMUJSVmRDUVdkTlFtNUNNVmx0ZUhCWmVrTkNhV2RaUzB0M1dVSkNRVWhYWlZGSlJVRm5VamhDU0c5QlpVRkNNa0ZPTURrS1RVZHlSM2g0UlhsWmVHdGxTRXBzYms1M1MybFRiRFkwTTJwNWRDODBaVXRqYjBGMlMyVTJUMEZCUVVKcGEwaDZLM1ozUVVGQlVVUkJSV04zVWxGSlp3cGFSVzg0WXpCbFExcElSV2cwZFhwNlNucEdlamxVSzBWbVUxUk9WSFJDTWtaSlNERTRkbGh3YTA5elEwbFJSRVV4VFZSMGFUbFNiMFJ1VWs4elUwVlVDakZhYTJGa05rWnZWSGd2YXpaNmRGRmpkMGxFVUcxdVVuaFVRVXRDWjJkeGFHdHFUMUJSVVVSQmQwNXVRVVJDYTBGcVFrSXdObVp0VGxoNE5sUnZZVU1LYkVabk1tdFBlRzVtVEVkbmNuWnZVak5HTlVkcVJIUjJSRUpDT0cwNVUxZFJUbnBNTWpFeGFsbHRVeTluSzFsaVlubFZRMDFESzJGa05tcEpTeXRsWmdwbE5GaFBTV3hvVEdOWGVHVmFZa0owVFdwTFUzSlFlRzF0TkdwU00wSkdVVkZQUWxJck9ISXlOME5wYjNsb2VHOVRjWFpNZFhjOVBRb3RMUzB0TFVWT1JDQkRSVkpVU1VaSlEwRlVSUzB0TFMwdCIsInNpZyI6IlRVVlJRMGxEWVhSb2JsUkljMlJtV25GSWNUTnBXRXhxVFdVd1ZGVTViRXhaYmxJeGVtazNNM0JSZFZobU5VdElRV2xDTWpOS2FDdG5VMll4VVVWRGJrRlRSMlZ3TW1VeVRVZHVVRmhwYjFWTVZqUjJRMGxUU2tKdWEwcGFaejA5In1dfSwiaGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6IjFiZDg4ZTA1NGY2OGE3ZDE3MzkzNjcyYjAzZmExOGZkNjRmMGRjZDVmY2M1NDAzNWMxOWZlNjQwMWNmMmNmNWUifSwicGF5bG9hZEhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI4Y2ViNGFiODEyNzczMTQ3M2E5ZWM4MTE0MGNiNjg0OWNmOGU5NzBjZGEzMmJhZWYwOTlkZjQ4YmEzMjY0NDQyIn19fX0="
}
],
"timestampVerificationData": null
},
"dsseEnvelope": {
"payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicGtnOm5wbS9zaWdzdG9yZUAyLjEuMCIsImRpZ2VzdCI6eyJzaGE1MTIiOiI5MGYyMjNmOTkyZTRjODhkZDA2OGNkMmE1ZmM1N2Y5ZDJiMzA3OTgzNDNkZDZlMzhmMjljMjQwZTA0YmEwOTBlZjgzMWY4NDQ5MDg0N2M0ZTgyYjkyMzJjNzhlOGEyNTg0NjNiMWU1NWMwZjc0NjlmNzMwMjY1MDA4ZmE2NjMzZiJ9fV0sInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjEiLCJwcmVkaWNhdGUiOnsiYnVpbGREZWZpbml0aW9uIjp7ImJ1aWxkVHlwZSI6Imh0dHBzOi8vc2xzYS1mcmFtZXdvcmsuZ2l0aHViLmlvL2dpdGh1Yi1hY3Rpb25zLWJ1aWxkdHlwZXMvd29ya2Zsb3cvdjEiLCJleHRlcm5hbFBhcmFtZXRlcnMiOnsid29ya2Zsb3ciOnsicmVmIjoicmVmcy9oZWFkcy9tYWluIiwicmVwb3NpdG9yeSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zaWdzdG9yZS9zaWdzdG9yZS1qcyIsInBhdGgiOiIuZ2l0aHViL3dvcmtmbG93cy9yZWxlYXNlLnltbCJ9fSwiaW50ZXJuYWxQYXJhbWV0ZXJzIjp7ImdpdGh1YiI6eyJldmVudF9uYW1lIjoicHVzaCIsInJlcG9zaXRvcnlfaWQiOiI0OTU1NzQ1NTUiLCJyZXBvc2l0b3J5X293bmVyX2lkIjoiNzEwOTYzNTMifX0sInJlc29sdmVkRGVwZW5kZW5jaWVzIjpbeyJ1cmkiOiJnaXQraHR0cHM6Ly9naXRodWIuY29tL3NpZ3N0b3JlL3NpZ3N0b3JlLWpzQHJlZnMvaGVhZHMvbWFpbiIsImRpZ2VzdCI6eyJnaXRDb21taXQiOiIyNmQxNjUxMzM4NmZmYWE3OTBiMWMzMmY5Mjc1NDRmMTMyMmU0MTk0In19XX0sInJ1bkRldGFpbHMiOnsiYnVpbGRlciI6eyJpZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL3J1bm5lci9naXRodWItaG9zdGVkIn0sIm1ldGFkYXRhIjp7Imludm9jYXRpb25JZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zaWdzdG9yZS9zaWdzdG9yZS1qcy9hY3Rpb25zL3J1bnMvNjAxNDQ4ODY2Ni9hdHRlbXB0cy8xIn19fX0=",
"payloadType": "application/vnd.in-toto+json",
"signatures": [
{
"sig": "MEQCICathnTHsdfZqHq3iXLjMe0TU9lLYnR1zi73pQuXf5KHAiB23Jh+gSf1QECnASGep2e2MGnPXioULV4vCISJBnkJZg==",
"keyid": ""
}
]
}
}

View file

@ -1,61 +1,55 @@
{
"mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.1",
"verificationMaterial": {
"x509CertificateChain": {
"certificates": [
{
"rawBytes": "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"
}
]
},
"tlogEntries": [
{
"logIndex": "33351527",
"logId": {
"keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="
},
"kindVersion": {
"kind": "intoto",
"version": "0.0.2"
},
"integratedTime": "1693323623",
"inclusionPromise": {
"signedEntryTimestamp": "MEYCIQDhWvNSLvnq5ZS3qTIgC7K2uQFeA0g8FEEjNo1UQxeubAIhALDrD1uIiUkk3tQNp/4gKT/9j8zEyyxi9Ti+qaD8q2vI"
},
"inclusionProof": {
"logIndex": "29188096",
"rootHash": "fbEijQTFeiQCldZqez/u/WcrNPk4nxXI5ihofHYjFUA=",
"treeSize": "29188099",
"hashes": [
"z7VKeAC2d2x18Vtxt7n40GS3gtc1xfRwjjxxzpy/Trw=",
"/Kd8ZuCLZ7MukSwpjaSgxKFl5X2vdHWk6/qpNrkiUJo=",
"vvkKs7IShUI15nVb9c5olPgBnL9r4uP7+d5KzV0hSjs=",
"Fg4p0WJZw8Lghrpxkx1SXgzfroTeIIrEgEbfgr9IdXY=",
"bH8NahqE+hQ58Qxhg0V5fYusFQ1xsaQ/rK6slWVRT5k=",
"HplNgZ3/afEHq52zcfL2s1AKisOYDdMCWK1jOu1tGyw=",
"uOPuC2YDmwZe989ZN3Lgh5CKMXh9HETrSNgf0jV0WkM=",
"eVsvWKnEZ1+Xo3Ba15DfEiIhhmlrEaIeb+VfYmx8KhY=",
"uLuBRins5nkqq2rqd17R27pQTUF+xetttC6MsmlUzd0=",
"jRUq4D8O+FI47Wbw96s7yHCu4qzWUxpIVfxQEeprDmc=",
"rXEsmEJN4PEoTU8US4qVtdIsGB1MCiRlGOepoiC99kM="
],
"checkpoint": {
"envelope": "rekor.sigstore.dev - 2605736670972794746\n29188099\nfbEijQTFeiQCldZqez/u/WcrNPk4nxXI5ihofHYjFUA=\nTimestamp: 1693323623528968756\n\n— rekor.sigstore.dev wNI9ajBEAiAK0YTbxRlhOZeeP+844Y+W7iz+hsFIF8x2NYsmuaxifAIgYUFSurlKwN7j5jCwpqSVrkbouQoYIYlyWU9Om16svmI=\n"
}
},
"canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjIiLCJraW5kIjoiaW50b3RvIiwic3BlYyI6eyJjb250ZW50Ijp7ImVudmVsb3BlIjp7InBheWxvYWRUeXBlIjoiYXBwbGljYXRpb24vdm5kLmluLXRvdG8ranNvbiIsInNpZ25hdHVyZXMiOlt7InB1YmxpY0tleSI6IkxTMHRMUzFDUlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVWQwUkVORFFtcDFaMEYzU1VKQlowbFZRMHBNYVhCVGREQTVTMHhHWXpCS1dXWjFSSEpUWVc0dkwweHpkME5uV1VsTGIxcEplbW93UlVGM1RYY0tUbnBGVmsxQ1RVZEJNVlZGUTJoTlRXTXliRzVqTTFKMlkyMVZkVnBIVmpKTlVqUjNTRUZaUkZaUlVVUkZlRlo2WVZka2VtUkhPWGxhVXpGd1ltNVNiQXBqYlRGc1drZHNhR1JIVlhkSWFHTk9UV3BOZDA5RVNUVk5WRlV3VFVSSmVsZG9ZMDVOYWsxM1QwUkpOVTFVVlRGTlJFbDZWMnBCUVUxR2EzZEZkMWxJQ2t0dldrbDZhakJEUVZGWlNVdHZXa2w2YWpCRVFWRmpSRkZuUVVWUVptMDJURkJZVVdWS1ZFTTRPVlZQY1dsT1YyMXVXbGxIYlZnMFZETnBURnBIYVRBS1JWWTBZbVpQYjAwNE5raDZZVGswV0hGNWRYZDRRVzlYY0VOUVpXTkdRMFZpUVdVNGJESmtaeTlsY2pOUE9VeEZSbkZQUTBKV2IzZG5aMVpYVFVFMFJ3cEJNVlZrUkhkRlFpOTNVVVZCZDBsSVowUkJWRUpuVGxaSVUxVkZSRVJCUzBKblozSkNaMFZHUWxGalJFRjZRV1JDWjA1V1NGRTBSVVpuVVZWbGNYQkRDbGhJY2pOd1kxVmhURE5GUmt0U0swdHpiWFZMVVhGdmQwaDNXVVJXVWpCcVFrSm5kMFp2UVZVek9WQndlakZaYTBWYVlqVnhUbXB3UzBaWGFYaHBORmtLV2tRNGQxbDNXVVJXVWpCU1FWRklMMEpHYTNkV05GcFdZVWhTTUdOSVRUWk1lVGx1WVZoU2IyUlhTWFZaTWpsMFRETk9jRm96VGpCaU0wcHNURE5PY0FwYU0wNHdZak5LYkV4WGNIcE1lVFZ1WVZoU2IyUlhTWFprTWpsNVlUSmFjMkl6WkhwTU0wcHNZa2RXYUdNeVZYVmxWekZ6VVVoS2JGcHVUWFpoUjFab0NscElUWFppVjBad1ltcEJOVUpuYjNKQ1owVkZRVmxQTDAxQlJVSkNRM1J2WkVoU2QyTjZiM1pNTTFKMllUSldkVXh0Um1wa1IyeDJZbTVOZFZveWJEQUtZVWhXYVdSWVRteGpiVTUyWW01U2JHSnVVWFZaTWpsMFRVSkpSME5wYzBkQlVWRkNaemM0ZDBGUlNVVkNTRUl4WXpKbmQwNW5XVXRMZDFsQ1FrRkhSQXAyZWtGQ1FYZFJiMDFxV210TlZGa3hUVlJOZWs5RVdtMWFiVVpvVG5wcmQxbHFSbXBOZWtwdFQxUkpNMDVVVVRCYWFrVjZUV3BLYkU1RVJUVk9SRUZXQ2tKbmIzSkNaMFZGUVZsUEwwMUJSVVZDUVdSVFdsZDRiRmxZVG14TlEwbEhRMmx6UjBGUlVVSm5OemgzUVZGVlJVWklUbkJhTTA0d1lqTktiRXd6VG5BS1dqTk9NR0l6U214TVYzQjZUVUl3UjBOcGMwZEJVVkZDWnpjNGQwRlJXVVZFTTBwc1dtNU5kbUZIVm1oYVNFMTJZbGRHY0dKcVFUZENaMjl5UW1kRlJRcEJXVTh2VFVGRlNVSkRNRTFMTW1nd1pFaENlazlwT0haa1J6bHlXbGMwZFZsWFRqQmhWemwxWTNrMWJtRllVbTlrVjBveFl6SldlVmt5T1hWa1IxWjFDbVJETldwaU1qQjNXbEZaUzB0M1dVSkNRVWRFZG5wQlFrTlJVbGhFUmxadlpFaFNkMk42YjNaTU1tUndaRWRvTVZscE5XcGlNakIyWXpKc2JtTXpVbllLWTIxVmRtTXliRzVqTTFKMlkyMVZkR0Z1VFhaTWJXUndaRWRvTVZscE9UTmlNMHB5V20xNGRtUXpUWFpqYlZaeldsZEdlbHBUTlRWaVYzaEJZMjFXYlFwamVUbHZXbGRHYTJONU9YUlpWMngxVFVSblIwTnBjMGRCVVZGQ1p6YzRkMEZSYjBWTFozZHZUV3BhYTAxVVdURk5WRTE2VDBSYWJWcHRSbWhPZW10M0NsbHFSbXBOZWtwdFQxUkpNMDVVVVRCYWFrVjZUV3BLYkU1RVJUVk9SRUZrUW1kdmNrSm5SVVZCV1U4dlRVRkZURUpCT0UxRVYyUndaRWRvTVZscE1XOEtZak5PTUZwWFVYZE9kMWxMUzNkWlFrSkJSMFIyZWtGQ1JFRlJjRVJEWkc5a1NGSjNZM3B2ZGt3eVpIQmtSMmd4V1drMWFtSXlNSFpqTW14dVl6TlNkZ3BqYlZWMll6SnNibU16VW5aamJWVjBZVzVOZDA5QldVdExkMWxDUWtGSFJIWjZRVUpFVVZGeFJFTm5lVTV0VVhoT2FsVjRUWHBOTkU1dFdtMVpWMFV6Q2s5VVFtbE5WMDE2VFcxWk5VMXFZekZPUkZKdFRWUk5lVTF0VlRCTlZHc3dUVUk0UjBOcGMwZEJVVkZDWnpjNGQwRlJORVZGVVhkUVkyMVdiV041T1c4S1dsZEdhMk41T1hSWlYyeDFUVUpyUjBOcGMwZEJVVkZDWnpjNGQwRlJPRVZEZDNkS1RrUnJNVTVVWXpCT1ZGVXhUVU56UjBOcGMwZEJVVkZDWnpjNGR3cEJVa0ZGU0ZGM1ltRklVakJqU0UwMlRIazVibUZZVW05a1YwbDFXVEk1ZEV3elRuQmFNMDR3WWpOS2JFMUNaMGREYVhOSFFWRlJRbWMzT0hkQlVrVkZDa05uZDBsT2VrVjNUMVJaZWs1VVRYZGFVVmxMUzNkWlFrSkJSMFIyZWtGQ1JXZFNXRVJHVm05a1NGSjNZM3B2ZGt3eVpIQmtSMmd4V1drMWFtSXlNSFlLWXpKc2JtTXpVblpqYlZWMll6SnNibU16VW5aamJWVjBZVzVOZGt4dFpIQmtSMmd4V1drNU0ySXpTbkphYlhoMlpETk5kbU50Vm5OYVYwWjZXbE0xTlFwaVYzaEJZMjFXYldONU9XOWFWMFpyWTNrNWRGbFhiSFZOUkdkSFEybHpSMEZSVVVKbk56aDNRVkpOUlV0bmQyOU5hbHByVFZSWk1VMVVUWHBQUkZwdENscHRSbWhPZW10M1dXcEdhazE2U20xUFZFa3pUbFJSTUZwcVJYcE5ha3BzVGtSRk5VNUVRVlZDWjI5eVFtZEZSVUZaVHk5TlFVVlZRa0ZaVFVKSVFqRUtZekpuZDFkbldVdExkMWxDUWtGSFJIWjZRVUpHVVZKTlJFVndiMlJJVW5kamVtOTJUREprY0dSSGFERlphVFZxWWpJd2RtTXliRzVqTTFKMlkyMVZkZ3BqTW14dVl6TlNkbU50VlhSaGJrMTJXVmRPTUdGWE9YVmplVGw1WkZjMWVreDZXWGROVkZFd1QwUm5NazVxV1haWldGSXdXbGN4ZDJSSVRYWk5WRUZYQ2tKbmIzSkNaMFZGUVZsUEwwMUJSVmRDUVdkTlFtNUNNVmx0ZUhCWmVrTkNhV2RaUzB0M1dVSkNRVWhYWlZGSlJVRm5VamhDU0c5QlpVRkNNa0ZPTURrS1RVZHlSM2g0UlhsWmVHdGxTRXBzYms1M1MybFRiRFkwTTJwNWRDODBaVXRqYjBGMlMyVTJUMEZCUVVKcGEwaDZLM1ozUVVGQlVVUkJSV04zVWxGSlp3cGFSVzg0WXpCbFExcElSV2cwZFhwNlNucEdlamxVSzBWbVUxUk9WSFJDTWtaSlNERTRkbGh3YTA5elEwbFJSRVV4VFZSMGFUbFNiMFJ1VWs4elUwVlVDakZhYTJGa05rWnZWSGd2YXpaNmRGRmpkMGxFVUcxdVVuaFVRVXRDWjJkeGFHdHFUMUJSVVVSQmQwNXVRVVJDYTBGcVFrSXdObVp0VGxoNE5sUnZZVU1LYkVabk1tdFBlRzVtVEVkbmNuWnZVak5HTlVkcVJIUjJSRUpDT0cwNVUxZFJUbnBNTWpFeGFsbHRVeTluSzFsaVlubFZRMDFESzJGa05tcEpTeXRsWmdwbE5GaFBTV3hvVEdOWGVHVmFZa0owVFdwTFUzSlFlRzF0TkdwU00wSkdVVkZQUWxJck9ISXlOME5wYjNsb2VHOVRjWFpNZFhjOVBRb3RMUzB0TFVWT1JDQkRSVkpVU1VaSlEwRlVSUzB0TFMwdCIsInNpZyI6IlRVVlJRMGxEWVhSb2JsUkljMlJtV25GSWNUTnBXRXhxVFdVd1ZGVTViRXhaYmxJeGVtazNNM0JSZFZobU5VdElRV2xDTWpOS2FDdG5VMll4VVVWRGJrRlRSMlZ3TW1VeVRVZHVVRmhwYjFWTVZqUjJRMGxUU2tKdWEwcGFaejA5In1dfSwiaGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6IjFiZDg4ZTA1NGY2OGE3ZDE3MzkzNjcyYjAzZmExOGZkNjRmMGRjZDVmY2M1NDAzNWMxOWZlNjQwMWNmMmNmNWUifSwicGF5bG9hZEhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI4Y2ViNGFiODEyNzczMTQ3M2E5ZWM4MTE0MGNiNjg0OWNmOGU5NzBjZGEzMmJhZWYwOTlkZjQ4YmEzMjY0NDQyIn19fX0="
}
],
"timestampVerificationData": null
},
"dsseEnvelope": {
"payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicGtnOm5wbS9zaWdzdG9yZUAyLjEuMCIsImRpZ2VzdCI6eyJzaGE1MTIiOiI5MGYyMjNmOTkyZTRjODhkZDA2OGNkMmE1ZmM1N2Y5ZDJiMzA3OTgzNDNkZDZlMzhmMjljMjQwZTA0YmEwOTBlZjgzMWY4NDQ5MDg0N2M0ZTgyYjkyMzJjNzhlOGEyNTg0NjNiMWU1NWMwZjc0NjlmNzMwMjY1MDA4ZmE2NjMzZiJ9fV0sInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjEiLCJwcmVkaWNhdGUiOnsiYnVpbGREZWZpbml0aW9uIjp7ImJ1aWxkVHlwZSI6Imh0dHBzOi8vc2xzYS1mcmFtZXdvcmsuZ2l0aHViLmlvL2dpdGh1Yi1hY3Rpb25zLWJ1aWxkdHlwZXMvd29ya2Zsb3cvdjEiLCJleHRlcm5hbFBhcmFtZXRlcnMiOnsid29ya2Zsb3ciOnsicmVmIjoicmVmcy9oZWFkcy9tYWluIiwicmVwb3NpdG9yeSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zaWdzdG9yZS9zaWdzdG9yZS1qcyIsInBhdGgiOiIuZ2l0aHViL3dvcmtmbG93cy9yZWxlYXNlLnltbCJ9fSwiaW50ZXJuYWxQYXJhbWV0ZXJzIjp7ImdpdGh1YiI6eyJldmVudF9uYW1lIjoicHVzaCIsInJlcG9zaXRvcnlfaWQiOiI0OTU1NzQ1NTUiLCJyZXBvc2l0b3J5X293bmVyX2lkIjoiNzEwOTYzNTMifX0sInJlc29sdmVkRGVwZW5kZW5jaWVzIjpbeyJ1cmkiOiJnaXQraHR0cHM6Ly9naXRodWIuY29tL3NpZ3N0b3JlL3NpZ3N0b3JlLWpzQHJlZnMvaGVhZHMvbWFpbiIsImRpZ2VzdCI6eyJnaXRDb21taXQiOiIyNmQxNjUxMzM4NmZmYWE3OTBiMWMzMmY5Mjc1NDRmMTMyMmU0MTk0In19XX0sInJ1bkRldGFpbHMiOnsiYnVpbGRlciI6eyJpZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL3J1bm5lci9naXRodWItaG9zdGVkIn0sIm1ldGFkYXRhIjp7Imludm9jYXRpb25JZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zaWdzdG9yZS9zaWdzdG9yZS1qcy9hY3Rpb25zL3J1bnMvNjAxNDQ4ODY2Ni9hdHRlbXB0cy8xIn19fX0=",
"payloadType": "application/vnd.in-toto+json",
"signatures": [
{
"sig": "MEQCICathnTHsdfZqHq3iXLjMe0TU9lLYnR1zi73pQuXf5KHAiB23Jh+gSf1QECnASGep2e2MGnPXioULV4vCISJBnkJZg==",
"keyid": ""
}
]
}
}
"mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json",
"verificationMaterial": {
"certificate": {
"rawBytes": "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"
},
"tlogEntries": [
{
"logIndex": "33351527",
"logId": {
"keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="
},
"kindVersion": {
"kind": "intoto",
"version": "0.0.2"
},
"integratedTime": "1693323623",
"inclusionPromise": {
"signedEntryTimestamp": "MEYCIQDhWvNSLvnq5ZS3qTIgC7K2uQFeA0g8FEEjNo1UQxeubAIhALDrD1uIiUkk3tQNp/4gKT/9j8zEyyxi9Ti+qaD8q2vI"
},
"inclusionProof": {
"logIndex": "29188096",
"rootHash": "fbEijQTFeiQCldZqez/u/WcrNPk4nxXI5ihofHYjFUA=",
"treeSize": "29188099",
"hashes": [
"z7VKeAC2d2x18Vtxt7n40GS3gtc1xfRwjjxxzpy/Trw=",
"/Kd8ZuCLZ7MukSwpjaSgxKFl5X2vdHWk6/qpNrkiUJo=",
"vvkKs7IShUI15nVb9c5olPgBnL9r4uP7+d5KzV0hSjs=",
"Fg4p0WJZw8Lghrpxkx1SXgzfroTeIIrEgEbfgr9IdXY=",
"bH8NahqE+hQ58Qxhg0V5fYusFQ1xsaQ/rK6slWVRT5k=",
"HplNgZ3/afEHq52zcfL2s1AKisOYDdMCWK1jOu1tGyw=",
"uOPuC2YDmwZe989ZN3Lgh5CKMXh9HETrSNgf0jV0WkM=",
"eVsvWKnEZ1+Xo3Ba15DfEiIhhmlrEaIeb+VfYmx8KhY=",
"uLuBRins5nkqq2rqd17R27pQTUF+xetttC6MsmlUzd0=",
"jRUq4D8O+FI47Wbw96s7yHCu4qzWUxpIVfxQEeprDmc=",
"rXEsmEJN4PEoTU8US4qVtdIsGB1MCiRlGOepoiC99kM="
],
"checkpoint": {
"envelope": "rekor.sigstore.dev - 2605736670972794746\n29188099\nfbEijQTFeiQCldZqez/u/WcrNPk4nxXI5ihofHYjFUA=\nTimestamp: 1693323623528968756\n\n— rekor.sigstore.dev wNI9ajBEAiAK0YTbxRlhOZeeP+844Y+W7iz+hsFIF8x2NYsmuaxifAIgYUFSurlKwN7j5jCwpqSVrkbouQoYIYlyWU9Om16svmI=\n"
}
},
"canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjIiLCJraW5kIjoiaW50b3RvIiwic3BlYyI6eyJjb250ZW50Ijp7ImVudmVsb3BlIjp7InBheWxvYWRUeXBlIjoiYXBwbGljYXRpb24vdm5kLmluLXRvdG8ranNvbiIsInNpZ25hdHVyZXMiOlt7InB1YmxpY0tleSI6IkxTMHRMUzFDUlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVWQwUkVORFFtcDFaMEYzU1VKQlowbFZRMHBNYVhCVGREQTVTMHhHWXpCS1dXWjFSSEpUWVc0dkwweHpkME5uV1VsTGIxcEplbW93UlVGM1RYY0tUbnBGVmsxQ1RVZEJNVlZGUTJoTlRXTXliRzVqTTFKMlkyMVZkVnBIVmpKTlVqUjNTRUZaUkZaUlVVUkZlRlo2WVZka2VtUkhPWGxhVXpGd1ltNVNiQXBqYlRGc1drZHNhR1JIVlhkSWFHTk9UV3BOZDA5RVNUVk5WRlV3VFVSSmVsZG9ZMDVOYWsxM1QwUkpOVTFVVlRGTlJFbDZWMnBCUVUxR2EzZEZkMWxJQ2t0dldrbDZhakJEUVZGWlNVdHZXa2w2YWpCRVFWRmpSRkZuUVVWUVptMDJURkJZVVdWS1ZFTTRPVlZQY1dsT1YyMXVXbGxIYlZnMFZETnBURnBIYVRBS1JWWTBZbVpQYjAwNE5raDZZVGswV0hGNWRYZDRRVzlYY0VOUVpXTkdRMFZpUVdVNGJESmtaeTlsY2pOUE9VeEZSbkZQUTBKV2IzZG5aMVpYVFVFMFJ3cEJNVlZrUkhkRlFpOTNVVVZCZDBsSVowUkJWRUpuVGxaSVUxVkZSRVJCUzBKblozSkNaMFZHUWxGalJFRjZRV1JDWjA1V1NGRTBSVVpuVVZWbGNYQkRDbGhJY2pOd1kxVmhURE5GUmt0U0swdHpiWFZMVVhGdmQwaDNXVVJXVWpCcVFrSm5kMFp2UVZVek9WQndlakZaYTBWYVlqVnhUbXB3UzBaWGFYaHBORmtLV2tRNGQxbDNXVVJXVWpCU1FWRklMMEpHYTNkV05GcFdZVWhTTUdOSVRUWk1lVGx1WVZoU2IyUlhTWFZaTWpsMFRETk9jRm96VGpCaU0wcHNURE5PY0FwYU0wNHdZak5LYkV4WGNIcE1lVFZ1WVZoU2IyUlhTWFprTWpsNVlUSmFjMkl6WkhwTU0wcHNZa2RXYUdNeVZYVmxWekZ6VVVoS2JGcHVUWFpoUjFab0NscElUWFppVjBad1ltcEJOVUpuYjNKQ1owVkZRVmxQTDAxQlJVSkNRM1J2WkVoU2QyTjZiM1pNTTFKMllUSldkVXh0Um1wa1IyeDJZbTVOZFZveWJEQUtZVWhXYVdSWVRteGpiVTUyWW01U2JHSnVVWFZaTWpsMFRVSkpSME5wYzBkQlVWRkNaemM0ZDBGUlNVVkNTRUl4WXpKbmQwNW5XVXRMZDFsQ1FrRkhSQXAyZWtGQ1FYZFJiMDFxV210TlZGa3hUVlJOZWs5RVdtMWFiVVpvVG5wcmQxbHFSbXBOZWtwdFQxUkpNMDVVVVRCYWFrVjZUV3BLYkU1RVJUVk9SRUZXQ2tKbmIzSkNaMFZGUVZsUEwwMUJSVVZDUVdSVFdsZDRiRmxZVG14TlEwbEhRMmx6UjBGUlVVSm5OemgzUVZGVlJVWklUbkJhTTA0d1lqTktiRXd6VG5BS1dqTk9NR0l6U214TVYzQjZUVUl3UjBOcGMwZEJVVkZDWnpjNGQwRlJXVVZFTTBwc1dtNU5kbUZIVm1oYVNFMTJZbGRHY0dKcVFUZENaMjl5UW1kRlJRcEJXVTh2VFVGRlNVSkRNRTFMTW1nd1pFaENlazlwT0haa1J6bHlXbGMwZFZsWFRqQmhWemwxWTNrMWJtRllVbTlrVjBveFl6SldlVmt5T1hWa1IxWjFDbVJETldwaU1qQjNXbEZaUzB0M1dVSkNRVWRFZG5wQlFrTlJVbGhFUmxadlpFaFNkMk42YjNaTU1tUndaRWRvTVZscE5XcGlNakIyWXpKc2JtTXpVbllLWTIxVmRtTXliRzVqTTFKMlkyMVZkR0Z1VFhaTWJXUndaRWRvTVZscE9UTmlNMHB5V20xNGRtUXpUWFpqYlZaeldsZEdlbHBUTlRWaVYzaEJZMjFXYlFwamVUbHZXbGRHYTJONU9YUlpWMngxVFVSblIwTnBjMGRCVVZGQ1p6YzRkMEZSYjBWTFozZHZUV3BhYTAxVVdURk5WRTE2VDBSYWJWcHRSbWhPZW10M0NsbHFSbXBOZWtwdFQxUkpNMDVVVVRCYWFrVjZUV3BLYkU1RVJUVk9SRUZrUW1kdmNrSm5SVVZCV1U4dlRVRkZURUpCT0UxRVYyUndaRWRvTVZscE1XOEtZak5PTUZwWFVYZE9kMWxMUzNkWlFrSkJSMFIyZWtGQ1JFRlJjRVJEWkc5a1NGSjNZM3B2ZGt3eVpIQmtSMmd4V1drMWFtSXlNSFpqTW14dVl6TlNkZ3BqYlZWMll6SnNibU16VW5aamJWVjBZVzVOZDA5QldVdExkMWxDUWtGSFJIWjZRVUpFVVZGeFJFTm5lVTV0VVhoT2FsVjRUWHBOTkU1dFdtMVpWMFV6Q2s5VVFtbE5WMDE2VFcxWk5VMXFZekZPUkZKdFRWUk5lVTF0VlRCTlZHc3dUVUk0UjBOcGMwZEJVVkZDWnpjNGQwRlJORVZGVVhkUVkyMVdiV041T1c4S1dsZEdhMk41T1hSWlYyeDFUVUpyUjBOcGMwZEJVVkZDWnpjNGQwRlJPRVZEZDNkS1RrUnJNVTVVWXpCT1ZGVXhUVU56UjBOcGMwZEJVVkZDWnpjNGR3cEJVa0ZGU0ZGM1ltRklVakJqU0UwMlRIazVibUZZVW05a1YwbDFXVEk1ZEV3elRuQmFNMDR3WWpOS2JFMUNaMGREYVhOSFFWRlJRbWMzT0hkQlVrVkZDa05uZDBsT2VrVjNUMVJaZWs1VVRYZGFVVmxMUzNkWlFrSkJSMFIyZWtGQ1JXZFNXRVJHVm05a1NGSjNZM3B2ZGt3eVpIQmtSMmd4V1drMWFtSXlNSFlLWXpKc2JtTXpVblpqYlZWMll6SnNibU16VW5aamJWVjBZVzVOZGt4dFpIQmtSMmd4V1drNU0ySXpTbkphYlhoMlpETk5kbU50Vm5OYVYwWjZXbE0xTlFwaVYzaEJZMjFXYldONU9XOWFWMFpyWTNrNWRGbFhiSFZOUkdkSFEybHpSMEZSVVVKbk56aDNRVkpOUlV0bmQyOU5hbHByVFZSWk1VMVVUWHBQUkZwdENscHRSbWhPZW10M1dXcEdhazE2U20xUFZFa3pUbFJSTUZwcVJYcE5ha3BzVGtSRk5VNUVRVlZDWjI5eVFtZEZSVUZaVHk5TlFVVlZRa0ZaVFVKSVFqRUtZekpuZDFkbldVdExkMWxDUWtGSFJIWjZRVUpHVVZKTlJFVndiMlJJVW5kamVtOTJUREprY0dSSGFERlphVFZxWWpJd2RtTXliRzVqTTFKMlkyMVZkZ3BqTW14dVl6TlNkbU50VlhSaGJrMTJXVmRPTUdGWE9YVmplVGw1WkZjMWVreDZXWGROVkZFd1QwUm5NazVxV1haWldGSXdXbGN4ZDJSSVRYWk5WRUZYQ2tKbmIzSkNaMFZGUVZsUEwwMUJSVmRDUVdkTlFtNUNNVmx0ZUhCWmVrTkNhV2RaUzB0M1dVSkNRVWhYWlZGSlJVRm5VamhDU0c5QlpVRkNNa0ZPTURrS1RVZHlSM2g0UlhsWmVHdGxTRXBzYms1M1MybFRiRFkwTTJwNWRDODBaVXRqYjBGMlMyVTJUMEZCUVVKcGEwaDZLM1ozUVVGQlVVUkJSV04zVWxGSlp3cGFSVzg0WXpCbFExcElSV2cwZFhwNlNucEdlamxVSzBWbVUxUk9WSFJDTWtaSlNERTRkbGh3YTA5elEwbFJSRVV4VFZSMGFUbFNiMFJ1VWs4elUwVlVDakZhYTJGa05rWnZWSGd2YXpaNmRGRmpkMGxFVUcxdVVuaFVRVXRDWjJkeGFHdHFUMUJSVVVSQmQwNXVRVVJDYTBGcVFrSXdObVp0VGxoNE5sUnZZVU1LYkVabk1tdFBlRzVtVEVkbmNuWnZVak5HTlVkcVJIUjJSRUpDT0cwNVUxZFJUbnBNTWpFeGFsbHRVeTluSzFsaVlubFZRMDFESzJGa05tcEpTeXRsWmdwbE5GaFBTV3hvVEdOWGVHVmFZa0owVFdwTFUzSlFlRzF0TkdwU00wSkdVVkZQUWxJck9ISXlOME5wYjNsb2VHOVRjWFpNZFhjOVBRb3RMUzB0TFVWT1JDQkRSVkpVU1VaSlEwRlVSUzB0TFMwdCIsInNpZyI6IlRVVlJRMGxEWVhSb2JsUkljMlJtV25GSWNUTnBXRXhxVFdVd1ZGVTViRXhaYmxJeGVtazNNM0JSZFZobU5VdElRV2xDTWpOS2FDdG5VMll4VVVWRGJrRlRSMlZ3TW1VeVRVZHVVRmhwYjFWTVZqUjJRMGxUU2tKdWEwcGFaejA5In1dfSwiaGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6IjFiZDg4ZTA1NGY2OGE3ZDE3MzkzNjcyYjAzZmExOGZkNjRmMGRjZDVmY2M1NDAzNWMxOWZlNjQwMWNmMmNmNWUifSwicGF5bG9hZEhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI4Y2ViNGFiODEyNzczMTQ3M2E5ZWM4MTE0MGNiNjg0OWNmOGU5NzBjZGEzMmJhZWYwOTlkZjQ4YmEzMjY0NDQyIn19fX0="
}
]
},
"dsseEnvelope": {
"payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicGtnOm5wbS9zaWdzdG9yZUAyLjEuMCIsImRpZ2VzdCI6eyJzaGE1MTIiOiI5MGYyMjNmOTkyZTRjODhkZDA2OGNkMmE1ZmM1N2Y5ZDJiMzA3OTgzNDNkZDZlMzhmMjljMjQwZTA0YmEwOTBlZjgzMWY4NDQ5MDg0N2M0ZTgyYjkyMzJjNzhlOGEyNTg0NjNiMWU1NWMwZjc0NjlmNzMwMjY1MDA4ZmE2NjMzZiJ9fV0sInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjEiLCJwcmVkaWNhdGUiOnsiYnVpbGREZWZpbml0aW9uIjp7ImJ1aWxkVHlwZSI6Imh0dHBzOi8vc2xzYS1mcmFtZXdvcmsuZ2l0aHViLmlvL2dpdGh1Yi1hY3Rpb25zLWJ1aWxkdHlwZXMvd29ya2Zsb3cvdjEiLCJleHRlcm5hbFBhcmFtZXRlcnMiOnsid29ya2Zsb3ciOnsicmVmIjoicmVmcy9oZWFkcy9tYWluIiwicmVwb3NpdG9yeSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zaWdzdG9yZS9zaWdzdG9yZS1qcyIsInBhdGgiOiIuZ2l0aHViL3dvcmtmbG93cy9yZWxlYXNlLnltbCJ9fSwiaW50ZXJuYWxQYXJhbWV0ZXJzIjp7ImdpdGh1YiI6eyJldmVudF9uYW1lIjoicHVzaCIsInJlcG9zaXRvcnlfaWQiOiI0OTU1NzQ1NTUiLCJyZXBvc2l0b3J5X293bmVyX2lkIjoiNzEwOTYzNTMifX0sInJlc29sdmVkRGVwZW5kZW5jaWVzIjpbeyJ1cmkiOiJnaXQraHR0cHM6Ly9naXRodWIuY29tL3NpZ3N0b3JlL3NpZ3N0b3JlLWpzQHJlZnMvaGVhZHMvbWFpbiIsImRpZ2VzdCI6eyJnaXRDb21taXQiOiIyNmQxNjUxMzM4NmZmYWE3OTBiMWMzMmY5Mjc1NDRmMTMyMmU0MTk0In19XX0sInJ1bkRldGFpbHMiOnsiYnVpbGRlciI6eyJpZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL3J1bm5lci9naXRodWItaG9zdGVkIn0sIm1ldGFkYXRhIjp7Imludm9jYXRpb25JZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9zaWdzdG9yZS9zaWdzdG9yZS1qcy9hY3Rpb25zL3J1bnMvNjAxNDQ4ODY2Ni9hdHRlbXB0cy8xIn19fX0=",
"payloadType": "application/vnd.in-toto+json",
"signatures": [
{
"sig": "MEQCICathnTHsdfZqHq3iXLjMe0TU9lLYnR1zi73pQuXf5KHAiB23Jh+gSf1QECnASGep2e2MGnPXioULV4vCISJBnkJZg=="
}
]
}
}

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,9 @@
{
"mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.1",
"mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json",
"verificationMaterial": {
"certificate": {
"rawBytes": "MIICnzCCAiWgAwIBAgIUVHwehOtGn4KSD1H8RI581MfbyewwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjIxMTA4MjI1ODA2WhcNMjIxMTA4MjMwODA2WjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGg6Hjxt2UNiJ1kwwq5XQIIwMZnJfVQ3bF01uZKteMdcV/3qhCmWOecoxRqwrbYTshGg9NyXcBbve6zKwZVTLeqOCAUQwggFAMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQU7WpR60sCpgfu04wcsjvCFxt0fMkwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4YZD8wHwYDVR0RAQH/BBUwE4ERYnJpYW5AZGVoYW1lci5jb20wLAYKKwYBBAGDvzABAQQeaHR0cHM6Ly9naXRodWIuY29tL2xvZ2luL29hdXRoMIGJBgorBgEEAdZ5AgQCBHsEeQB3AHUA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGEWXcR8AAABAMARjBEAiBRTrGE5Y1EnYniaJB+nsv89VaYx3QZjocEin3r91wfkAIgMss+fssu5SLQkn7WDTKXgow7SxbHYSZj3ykxArVnuzEwCgYIKoZIzj0EAwMDaAAwZQIxAPjSGddLIvyUMGIkZ+u6JhE9p1Njt3dEtwYkMxfnEV2k7MH1BVmxg9PsJjqycfi+eAIwDaKn2CdOxKsxcgYNi4HviEnZqxmeDyo2YFItzpHfIMQmcRSl91UeOSC8+PuGgwMK"
},
"tlogEntries": [
{
"logIndex": "6751924",
@ -13,35 +16,56 @@
},
"integratedTime": "1667948287",
"inclusionPromise": {
"signedEntryTimestamp": "MEQCIEzguFRaGzOpMw9JJGUfqSJQ11qlzpcyVCkZfZYPwpLCAiBzdU4LnjtVKYCfyoTImFh3OLFWeOKygtS47Z8fp1GYHg=="
"signedEntryTimestamp": "MEQCIFC8EPrNU+kRCqHOJaGuw3NAFkJGYu8mssUaq71sR98pAiA5+SpNdFL5RrjyhulMo3t5xcc03srLlQmKx42LRiqGew=="
},
"inclusionProof": {
"logIndex": "2588493",
"rootHash": "N40Xn7VxprmSXoUSY27Bs6T2t0JvHShIY/7ekL0/p6U=",
"treeSize": "115826880",
"hashes": [
"qvPXILBiRJD+OZ8vUgQLlRe5QmJsbQgoKDYXbcQplZk=",
"ian1jlZJxuli49MJF79fN6RiMaQO8dj7Wk2o/gVJqTg=",
"4L82HI4fzDUm6Jl+jPDaotc3bWW9y9h08g5sJGavPko=",
"X3+ZmsxVTa8t+uRGaK4vgzJVAxjZL+5o35ueQA3WaRc=",
"Z6I4B7xGG98tCAWz7rdIxW36r8Uz2vPr+wZAiVJqLyU=",
"WTb/xFvgwNmpinr1+xKCbNZOGo8L6GN8oZ+snwmYESw=",
"lFxAqYOFdddHV349DzPLmsyPzCfzimnNKWk1itLLwy8=",
"BbtQkfipdk2Xwc3ijUSX5V0bxHNuPvbjq6csMZGrBh4=",
"8/XdI9PzRMcytBFkEv9WbIMNJaHkkFgZV39VNAzf6ho=",
"KmwX1cdeUfdQlFjqvqLQxKaOBoZ4/aIo2bUo9WzrGRc=",
"nffHMg5IaQx0gI0QG0A2cqRlajxbh7v6kdWKpQBowKY=",
"4n+4WqZcfi237GTZjbCgWwhN/oUnzHXSh67xV3R4GTE=",
"tfxH1EZ2uVk8MeHZ/7cxcSL1NALf27pfII4YVRfrMFU=",
"bdkHN9diWTXM0z5GECHlDIMvSl8koq33Vd8mSdNrhhY=",
"abpenKLgpX4ElLQbHYkjZzj0QptcTE9yujFeVSmMOtw=",
"qeGjNnuDqq2S63UDs3gJ2cfvolHGXREL/fc30SXYbFk=",
"ucRPSmGLhm/SyHL7chQ5vBEFull08HzsqtAC0TQ91tY=",
"EiS8ntcvGnB1xcGZg9Cf3fTkV1wBcJNVtSWKIYVZqAU=",
"Mx1LEx7szsPd62CGkL6HM+NWkOy9YwZTwukJEVgH7Cw=",
"s2Z13KVYurVY6F1AUhr8Uby4RE3RXW1XEC2tWWdzCjI=",
"QRfYxLEHh/FwMZqWnxNNW+x3lY7o3LM86BW+z0MpMN4=",
"J0dGjQ7V5bETi7p7eWg2ephCQ32QBLMWY5HxFcuGfR4=",
"uFGzOQorMYmYZ2yumLpgr1tvXvZaL+tTTCqaXa7Hdds=",
"Lksw/hm/y+1p33SaEF8/60gPvFVNkueBpDWJ1tAVcAo=",
"Soaoms+sNcJd3K95DWx//GJEbZPyr/e4cUVyLXK9tnk=",
"WcosyVcuwpv56nBkSbKEnSPbHesdKOoUykqVThLEqoo=",
"gY2fcNwGuA3cp7tQHZoB084DsKFwbF4tW78KgehHwfE="
],
"checkpoint": {
"envelope": "rekor.sigstore.dev - 2605736670972794746\n115826880\nN40Xn7VxprmSXoUSY27Bs6T2t0JvHShIY/7ekL0/p6U=\n\n— rekor.sigstore.dev wNI9ajBEAiBNjSQhOIg1Ch0UbbX+JZj5y//ajY0isa4dJsVajHo2ogIgGDm73+f2+vbJgbSqtqmPdXfb6Rm/vEIF3cli7j1KZ0I=\n"
}
},
"canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjIiLCJraW5kIjoiaW50b3RvIiwic3BlYyI6eyJjb250ZW50Ijp7ImVudmVsb3BlIjp7InBheWxvYWRUeXBlIjoidGV4dC9wbGFpbiIsInNpZ25hdHVyZXMiOlt7InB1YmxpY0tleSI6IkxTMHRMUzFDUlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVU51ZWtORFFXbFhaMEYzU1VKQlowbFZWa2gzWldoUGRFZHVORXRUUkRGSU9GSkpOVGd4VFdaaWVXVjNkME5uV1VsTGIxcEplbW93UlVGM1RYY0tUbnBGVmsxQ1RVZEJNVlZGUTJoTlRXTXliRzVqTTFKMlkyMVZkVnBIVmpKTlVqUjNTRUZaUkZaUlVVUkZlRlo2WVZka2VtUkhPWGxhVXpGd1ltNVNiQXBqYlRGc1drZHNhR1JIVlhkSWFHTk9UV3BKZUUxVVFUUk5ha2t4VDBSQk1sZG9ZMDVOYWtsNFRWUkJORTFxVFhkUFJFRXlWMnBCUVUxR2EzZEZkMWxJQ2t0dldrbDZhakJEUVZGWlNVdHZXa2w2YWpCRVFWRmpSRkZuUVVWSFp6WklhbmgwTWxWT2FVb3hhM2QzY1RWWVVVbEpkMDFhYmtwbVZsRXpZa1l3TVhVS1drdDBaVTFrWTFZdk0zRm9RMjFYVDJWamIzaFNjWGR5WWxsVWMyaEhaemxPZVZoalFtSjJaVFo2UzNkYVZsUk1aWEZQUTBGVlVYZG5aMFpCVFVFMFJ3cEJNVlZrUkhkRlFpOTNVVVZCZDBsSVowUkJWRUpuVGxaSVUxVkZSRVJCUzBKblozSkNaMFZHUWxGalJFRjZRV1JDWjA1V1NGRTBSVVpuVVZVM1YzQlNDall3YzBOd1oyWjFNRFIzWTNOcWRrTkdlSFF3WmsxcmQwaDNXVVJXVWpCcVFrSm5kMFp2UVZVek9WQndlakZaYTBWYVlqVnhUbXB3UzBaWGFYaHBORmtLV2tRNGQwaDNXVVJXVWpCU1FWRklMMEpDVlhkRk5FVlNXVzVLY0ZsWE5VRmFSMVp2V1ZjeGJHTnBOV3BpTWpCM1RFRlpTMHQzV1VKQ1FVZEVkbnBCUWdwQlVWRmxZVWhTTUdOSVRUWk1lVGx1WVZoU2IyUlhTWFZaTWpsMFRESjRkbG95YkhWTU1qbG9aRmhTYjAxSlIwcENaMjl5UW1kRlJVRmtXalZCWjFGRENrSkljMFZsVVVJelFVaFZRVE5VTUhkaGMySklSVlJLYWtkU05HTnRWMk16UVhGS1MxaHlhbVZRU3pNdmFEUndlV2RET0hBM2J6UkJRVUZIUlZkWVkxSUtPRUZCUVVKQlRVRlNha0pGUVdsQ1VsUnlSMFUxV1RGRmJsbHVhV0ZLUWl0dWMzWTRPVlpoV1hnelVWcHFiMk5GYVc0emNqa3hkMlpyUVVsblRYTnpLd3BtYzNOMU5WTk1VV3R1TjFkRVZFdFlaMjkzTjFONFlraFpVMXBxTTNscmVFRnlWbTUxZWtWM1EyZFpTVXR2V2tsNmFqQkZRWGROUkdGQlFYZGFVVWw0Q2tGUWFsTkhaR1JNU1haNVZVMUhTV3RhSzNVMlNtaEZPWEF4VG1wME0yUkZkSGRaYTAxNFptNUZWakpyTjAxSU1VSldiWGhuT1ZCelNtcHhlV05tYVNzS1pVRkpkMFJoUzI0eVEyUlBlRXR6ZUdObldVNXBORWgyYVVWdVduRjRiV1ZFZVc4eVdVWkpkSHB3U0daSlRWRnRZMUpUYkRreFZXVlBVME00SzFCMVJ3cG5kMDFMQ2kwdExTMHRSVTVFSUVORlVsUkpSa2xEUVZSRkxTMHRMUzBLIiwic2lnIjoiVFVWVlEwbERWV2hCVm1WM1puZExiR3MxWmxaNmNGSkVWVkJvUlhjNVR6aEpNbkI0UXpWdVZHNVFabGxFUW5OUFFXbEZRVEJhUm5Gek9UbFJaMUk1YlVGMFJrMVhkRmR5VDJwdFZVTTBOM3BuWVc5dmJFdEpiMHhJTDA5M1pFMDkifV19LCJoYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiZGNiNDkyNTljODY2MDdjMzQ2MzVkYWJiNDQzMWYwNjVlOWE3YTczNDcwNGNiNzNmMGFhMGY2YWFhMzg5NmEwNCJ9LCJwYXlsb2FkSGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6IjY4ZTY1NmIyNTFlNjdlODM1OGJlZjg0ODNhYjBkNTFjNjYxOWYzZTdhMWE5ZjBlNzU4MzhkNDFmZjM2OGY3MjgifX19fQ=="
}
],
"timestampVerificationData": {
"rfc3161Timestamps": []
},
"x509CertificateChain": {
"certificates": [
{
"rawBytes": "MIICnzCCAiWgAwIBAgIUVHwehOtGn4KSD1H8RI581MfbyewwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjIxMTA4MjI1ODA2WhcNMjIxMTA4MjMwODA2WjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGg6Hjxt2UNiJ1kwwq5XQIIwMZnJfVQ3bF01uZKteMdcV/3qhCmWOecoxRqwrbYTshGg9NyXcBbve6zKwZVTLeqOCAUQwggFAMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQU7WpR60sCpgfu04wcsjvCFxt0fMkwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4YZD8wHwYDVR0RAQH/BBUwE4ERYnJpYW5AZGVoYW1lci5jb20wLAYKKwYBBAGDvzABAQQeaHR0cHM6Ly9naXRodWIuY29tL2xvZ2luL29hdXRoMIGJBgorBgEEAdZ5AgQCBHsEeQB3AHUA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGEWXcR8AAABAMARjBEAiBRTrGE5Y1EnYniaJB+nsv89VaYx3QZjocEin3r91wfkAIgMss+fssu5SLQkn7WDTKXgow7SxbHYSZj3ykxArVnuzEwCgYIKoZIzj0EAwMDaAAwZQIxAPjSGddLIvyUMGIkZ+u6JhE9p1Njt3dEtwYkMxfnEV2k7MH1BVmxg9PsJjqycfi+eAIwDaKn2CdOxKsxcgYNi4HviEnZqxmeDyo2YFItzpHfIMQmcRSl91UeOSC8+PuGgwMK"
},
{
"rawBytes": "MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV77LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjpKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZIzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJRnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsPmygUY7Ii2zbdCdliiow="
},
{
"rawBytes": "MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxexX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92jYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRYwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCMWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ"
}
]
}
"timestampVerificationData": {}
},
"dsseEnvelope": {
"payload": "aGVsbG8sIHdvcmxkIQ==",
"payloadType": "text/plain",
"signatures": [
{
"sig": "NEUCICUhAVewfwKlk5fVzpRDUPhEw9O8I2pxC5nTnPfYDBsOAiEA0ZFqs99QgR9mAtFMWtWrOjmUC47zgaoolKIoLH/OwdM=",
"keyid": ""
"sig": "NEUCICUhAVewfwKlk5fVzpRDUPhEw9O8I2pxC5nTnPfYDBsOAiEA0ZFqs99QgR9mAtFMWtWrOjmUC47zgaoolKIoLH/OwdM="
}
]
}

View file

@ -32,22 +32,22 @@ func NewTrustedRootCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Com
Long: heredoc.Docf(`
### NOTE: This feature is currently in beta, and subject to change.
Output contents for a trusted_root.jsonl file, likely for offline verification.
Output contents for a trusted_root.jsonl file, likely for offline verification.
When using %[1]sgh attestation verify%[1]s, if your machine is on the internet,
this will happen automatically. But to do offline verification, you need to
supply a trusted root file with %[1]s--custom-trusted-root%[1]s; this command
will help you fetch a %[1]strusted_root.jsonl%[1]s file for that purpose.
When using %[1]sgh attestation verify%[1]s, if your machine is on the internet,
this will happen automatically. But to do offline verification, you need to
supply a trusted root file with %[1]s--custom-trusted-root%[1]s; this command
will help you fetch a %[1]strusted_root.jsonl%[1]s file for that purpose.
You can call this command without any flags to get a trusted root file covering
the Sigstore Public Good Instance as well as GitHub's Sigstore instance.
You can call this command without any flags to get a trusted root file covering
the Sigstore Public Good Instance as well as GitHub's Sigstore instance.
Otherwise you can use %[1]s--tuf-url%[1]s to specify the URL of a custom TUF
repository mirror, and %[1]s--tuf-root%[1]s should be the path to the
%[1]sroot.json%[1]s file that you securely obtained out-of-band.
Otherwise you can use %[1]s--tuf-url%[1]s to specify the URL of a custom TUF
repository mirror, and %[1]s--tuf-root%[1]s should be the path to the
%[1]sroot.json%[1]s file that you securely obtained out-of-band.
If you just want to verify the integrity of your local TUF repository, and don't
want the contents of a trusted_root.jsonl file, use %[1]s--verify-only%[1]s.
If you just want to verify the integrity of your local TUF repository, and don't
want the contents of a trusted_root.jsonl file, use %[1]s--verify-only%[1]s.
`, "`"),
Example: heredoc.Doc(`
# Get a trusted_root.jsonl for both Sigstore Public Good and GitHub's instance

View file

@ -1,163 +1,167 @@
{
"signatures": [
{
"keyid": "a10513a5ab61acd0c6b6fbe0504856ead18f3b17c4fabbe3fa848c79a5a187cf",
"sig": "304402203c8f5f7443f7052923e82f9ca0b1bb61a33498444076a2f43e1285a47f6e562d022014de99a7e5413440896b6804944e3c49390cfe6e617211b8dc42a8e67675bc13"
},
{
"keyid": "d6a89e23fb22801a0d1186bf1bdd007e228f65a8aa9964d24d06cb5fbb0ce91c",
"sig": "3044022009a20307f974af7e05cc9564eea497f45062e3b21272d1062713b3d22c868298022059d032ad973a28bdbd03959cf96b21398b6b6e2ca618c17ce6c13712246343a2"
},
{
"keyid": "539dde44014c850fe6eeb8b299eb7dae2e1f4bf83454b949e98aa73542cdc65a",
"sig": "3045022100edd270d36d0c8468b9a1f2ef1c81a270c72ffd50c65bca0ed1ebd424df09f64b022002b27ffafd7bc5bdfc25281b5b9b597cf2d67d4eeb4af2ff45eb3e666b860c21"
},
{
"keyid": "88737ccdac7b49cc237e9aaead81be2a40278b886a693d8149a19cf543f093d3",
"sig": "30460221008d7d95434e576d5876b2db30fd645505ca546618bbc7a8e4b39f64e6a36df9ad022100c00a5294e4ddd02d48d28918b87a06bdfdeccd0618ecdcec29bb2597a05fe474"
},
{
"keyid": "5e01c9a0b2641a8965a4a74e7df0bc7b2d8278a2c3ca0cf7a3f2f783d3c69800",
"sig": "30450220215fb3d19d94560a3a2a6067a71c92daf867d13700c9500c4c32d8009a48a634022100df9fb6cee786313bf6c363daac4de39b3dd531f211f81d2391c41bd2d0f91a80"
},
{
"keyid": "4f4d1dd75f2d7f3860e3a068d7bed90dec5f0faafcbe1ace7fb7d95d29e07228",
"sig": "304502204091ac5e61b6462d262ecc8442781dd09843bed39942a95a4884c8c6a2c212ef022100dcee86392748f48950d04d539ac1a6643ed1f0b4bd6856f8aeb5a135826c846f"
},
{
"keyid": "eb8eff37f93af2faaba519f341decec3cecd3eeafcace32966db9723842c8a62",
"sig": "30460221009188548601a43b501223caeefca4876ae892e18a85c885004b4c8aeeb05a4421022100abdcc72d94597f8297d6297897ff96f285168dbe6b3d57f846dbc7a2948d2935"
},
{
"keyid": "8b498a80a1b7af188c10c9abdf6aade81d14faaffcde2abcd6063baa673ebd12",
"sig": "3046022100b440561545d48759dc4140cda9f8af7c9405a101d6136dd0a26edd6562b7064f022100cafa917ed90350494e47d226b64a8ec63ef5ceebb8ba4d2dec2ce018e4ad402a"
}
"signatures": [
{
"keyid": "4f4d1dd75f2d7f3860e3a068d7bed90dec5f0faafcbe1ace7fb7d95d29e07228",
"sig": ""
},
{
"keyid": "eb8eff37f93af2faaba519f341decec3cecd3eeafcace32966db9723842c8a62",
"sig": ""
},
{
"keyid": "539dde44014c850fe6eeb8b299eb7dae2e1f4bf83454b949e98aa73542cdc65a",
"sig": ""
},
{
"keyid": "a10513a5ab61acd0c6b6fbe0504856ead18f3b17c4fabbe3fa848c79a5a187cf",
"sig": "3046022100ca341d3ba2ef7657d69c2825729959681f55aec497b612e81a547e2abb616b49022100cd605b412a3d991f92e0818e07e60383bbd23904723eec221d6e39fdfeae3104"
},
{
"keyid": "5e01c9a0b2641a8965a4a74e7df0bc7b2d8278a2c3ca0cf7a3f2f783d3c69800",
"sig": "3046022100d0f70effe60d6a18319e2890088cd01d45c654ee6d2ce1d5c3cdcf2dc7f637570221008f947a2d7334d948f1c4794b0a465f1dfb99a578dd8d1f4563cee0581f457db2"
},
{
"keyid": "54809115b40137aac01af4b7ac2408c77ea0d58fa4dad48fc3196497d2a26f44",
"sig": "304502201ae931db1c48020fb37af54d446ac856306f619dfc3f93ddcff70d2880e443dc022100992b70451aa74805adef24e85ec352e598812267f623979bd4ce719b66b62d22"
},
{
"keyid": "88737ccdac7b49cc237e9aaead81be2a40278b886a693d8149a19cf543f093d3",
"sig": "3045022023bba8e14c177609f43873aa0087ef983ddd2bad9a0a832c0cf279e1be8798f2022100facfaecc1d7ee793042eaaa6970fb9ca700c3bdbf4ee43ed0f8d0fc3aef96563"
},
{
"keyid": "d6a89e23fb22801a0d1186bf1bdd007e228f65a8aa9964d24d06cb5fbb0ce91c",
"sig": "3046022100d2f6cceb05d135ce6a6ce7fe1dc76c24508154ad71c433028e64ca95ba716ffb022100f0592d60eb67508dd5f9cc593a4cca33bbaf94882c3d74a560fda845a456c6cc"
},
{
"keyid": "8b498a80a1b7af188c10c9abdf6aade81d14faaffcde2abcd6063baa673ebd12",
"sig": "30450221009af2f0c534ed92de909a3b727f7101319c18e10623de8f48a0eba980d3d54d830220095842b16c58567c71f9dfa0b54e79daca1b2fecf3cb2ea4ee6d8393bdf93294"
}
],
"signed": {
"_type": "root",
"consistent_snapshot": true,
"expires": "2025-04-11T14:36:57Z",
"keys": {
"4f4d1dd75f2d7f3860e3a068d7bed90dec5f0faafcbe1ace7fb7d95d29e07228": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENki7aZVips5SgRzCd/Om0CGzQKY/\nnv84giqVDmdwb2ys82Z6soFLasvYYEEQcwqaC170n9gr93wHUgPc796uJA==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@ashtom"
},
"539dde44014c850fe6eeb8b299eb7dae2e1f4bf83454b949e98aa73542cdc65a": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAElD0o2sOZN9n3RKQ7PtMLAoXj+2Ai\nn4PKT/pfnzDlNLrD3VTQwCc4sR4t+OLu4KQ+qk+kXkR9YuBsu3bdJZ1OWw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@nerdneha"
},
"54809115b40137aac01af4b7ac2408c77ea0d58fa4dad48fc3196497d2a26f44": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEimKcdST+ORD+g0aGEFDOVZDAaIYg\nIgesNKiIe2L7MUsYx5UHhzQ08quvew13eYSCNJnfwooFZu7cdTu8AwqFjQ==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@alexiswales"
},
"88737ccdac7b49cc237e9aaead81be2a40278b886a693d8149a19cf543f093d3": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBagkskNOpOTbetTX5CdnvMy+LiWn\nonRrNrqAHL4WgiebH7Uig7GLhC3bkeA/qgb926/vr9qhOPG9Buj2HatrPw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@gregose"
},
"8b498a80a1b7af188c10c9abdf6aade81d14faaffcde2abcd6063baa673ebd12": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7IEoVNwrprchXGhT5sAhSax7SOd3\n8duuISghCzfmHdKJWSbV2wJRamRiUVRtmA83K/qm5cT20WXMCT5QeM/D3A==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@trevrosen"
},
"a10513a5ab61acd0c6b6fbe0504856ead18f3b17c4fabbe3fa848c79a5a187cf": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC2wJ3xscyXxBLybJ9FVjwkyQMe53\nRHUz77AjMO8MzVaT8xw6ZvJqdNZiytYtigWULlINxw6frNsWJKb/f7lC8A==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@kommendorkapten"
},
"d6a89e23fb22801a0d1186bf1bdd007e228f65a8aa9964d24d06cb5fbb0ce91c": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDdORwcruW3gqAgaLjH/nNdGMB4kQ\nAvA+wD6DyO4P/wR8ee2ce83NZHq1ZADKhve0rlYKaKy3CqyQ5SmlZ36Zhw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@krukow"
},
"eb8eff37f93af2faaba519f341decec3cecd3eeafcace32966db9723842c8a62": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENynVdQnM9h7xU71G7PiJpQaDemub\nkbjsjYwLlPJTQVuxQO8WeIpJf8MEh5rf01t2dDIuCsZ5gRx+QvDv0UzfsA==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@mph4"
},
"eb9799b483affac9da87ef4c9ea467928415c961349e607e5e6e485679b07f8f": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENKNcNcX+d73lS1TRFb9Vnp8JvOoh\nzYQ+in43iGenbG8RGo9L/6FJ2hoRbVU6xskvyuErcdPbCdI4GxrQ5i8hkw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-online-uri": "azurekms://production-tuf-root.vault.azure.net/keys/Online-Key/aaf375fd8ed24acb949a5cc173700b05"
}
},
"roles": {
"root": {
"keyids": [
"a10513a5ab61acd0c6b6fbe0504856ead18f3b17c4fabbe3fa848c79a5a187cf",
"4f4d1dd75f2d7f3860e3a068d7bed90dec5f0faafcbe1ace7fb7d95d29e07228",
"88737ccdac7b49cc237e9aaead81be2a40278b886a693d8149a19cf543f093d3",
"d6a89e23fb22801a0d1186bf1bdd007e228f65a8aa9964d24d06cb5fbb0ce91c",
"eb8eff37f93af2faaba519f341decec3cecd3eeafcace32966db9723842c8a62",
"8b498a80a1b7af188c10c9abdf6aade81d14faaffcde2abcd6063baa673ebd12",
"539dde44014c850fe6eeb8b299eb7dae2e1f4bf83454b949e98aa73542cdc65a",
"54809115b40137aac01af4b7ac2408c77ea0d58fa4dad48fc3196497d2a26f44"
],
"signed": {
"_type": "root",
"consistent_snapshot": true,
"expires": "2024-06-23T08:29:18Z",
"keys": {
"4f4d1dd75f2d7f3860e3a068d7bed90dec5f0faafcbe1ace7fb7d95d29e07228": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENki7aZVips5SgRzCd/Om0CGzQKY/\nnv84giqVDmdwb2ys82Z6soFLasvYYEEQcwqaC170n9gr93wHUgPc796uJA==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@ashtom"
},
"539dde44014c850fe6eeb8b299eb7dae2e1f4bf83454b949e98aa73542cdc65a": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAElD0o2sOZN9n3RKQ7PtMLAoXj+2Ai\nn4PKT/pfnzDlNLrD3VTQwCc4sR4t+OLu4KQ+qk+kXkR9YuBsu3bdJZ1OWw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@nerdneha"
},
"5e01c9a0b2641a8965a4a74e7df0bc7b2d8278a2c3ca0cf7a3f2f783d3c69800": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC9RNAsuDCNO6T7qA7Y5F8orw2tIW\nr7rUr4ffxvzTMrbkVtjR/trtE0q0+T0zQ8TWLyI6EYMwb947ej2ItfkOyA==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@jacobdepriest"
},
"88737ccdac7b49cc237e9aaead81be2a40278b886a693d8149a19cf543f093d3": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBagkskNOpOTbetTX5CdnvMy+LiWn\nonRrNrqAHL4WgiebH7Uig7GLhC3bkeA/qgb926/vr9qhOPG9Buj2HatrPw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@gregose"
},
"8b498a80a1b7af188c10c9abdf6aade81d14faaffcde2abcd6063baa673ebd12": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7IEoVNwrprchXGhT5sAhSax7SOd3\n8duuISghCzfmHdKJWSbV2wJRamRiUVRtmA83K/qm5cT20WXMCT5QeM/D3A==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@trevrosen"
},
"a10513a5ab61acd0c6b6fbe0504856ead18f3b17c4fabbe3fa848c79a5a187cf": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC2wJ3xscyXxBLybJ9FVjwkyQMe53\nRHUz77AjMO8MzVaT8xw6ZvJqdNZiytYtigWULlINxw6frNsWJKb/f7lC8A==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@kommendorkapten"
},
"d6a89e23fb22801a0d1186bf1bdd007e228f65a8aa9964d24d06cb5fbb0ce91c": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDdORwcruW3gqAgaLjH/nNdGMB4kQ\nAvA+wD6DyO4P/wR8ee2ce83NZHq1ZADKhve0rlYKaKy3CqyQ5SmlZ36Zhw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@krukow"
},
"eb8eff37f93af2faaba519f341decec3cecd3eeafcace32966db9723842c8a62": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENynVdQnM9h7xU71G7PiJpQaDemub\nkbjsjYwLlPJTQVuxQO8WeIpJf8MEh5rf01t2dDIuCsZ5gRx+QvDv0UzfsA==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@mph4"
},
"eb9799b483affac9da87ef4c9ea467928415c961349e607e5e6e485679b07f8f": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENKNcNcX+d73lS1TRFb9Vnp8JvOoh\nzYQ+in43iGenbG8RGo9L/6FJ2hoRbVU6xskvyuErcdPbCdI4GxrQ5i8hkw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-online-uri": "azurekms://production-tuf-root.vault.azure.net/keys/Online-Key/aaf375fd8ed24acb949a5cc173700b05"
}
},
"roles": {
"root": {
"keyids": [
"a10513a5ab61acd0c6b6fbe0504856ead18f3b17c4fabbe3fa848c79a5a187cf",
"4f4d1dd75f2d7f3860e3a068d7bed90dec5f0faafcbe1ace7fb7d95d29e07228",
"88737ccdac7b49cc237e9aaead81be2a40278b886a693d8149a19cf543f093d3",
"5e01c9a0b2641a8965a4a74e7df0bc7b2d8278a2c3ca0cf7a3f2f783d3c69800",
"d6a89e23fb22801a0d1186bf1bdd007e228f65a8aa9964d24d06cb5fbb0ce91c",
"eb8eff37f93af2faaba519f341decec3cecd3eeafcace32966db9723842c8a62",
"8b498a80a1b7af188c10c9abdf6aade81d14faaffcde2abcd6063baa673ebd12",
"539dde44014c850fe6eeb8b299eb7dae2e1f4bf83454b949e98aa73542cdc65a"
],
"threshold": 3
},
"snapshot": {
"keyids": [
"eb9799b483affac9da87ef4c9ea467928415c961349e607e5e6e485679b07f8f"
],
"threshold": 1,
"x-tuf-on-ci-expiry-period": 21,
"x-tuf-on-ci-signing-period": 7
},
"targets": {
"keyids": [
"a10513a5ab61acd0c6b6fbe0504856ead18f3b17c4fabbe3fa848c79a5a187cf",
"4f4d1dd75f2d7f3860e3a068d7bed90dec5f0faafcbe1ace7fb7d95d29e07228",
"88737ccdac7b49cc237e9aaead81be2a40278b886a693d8149a19cf543f093d3",
"5e01c9a0b2641a8965a4a74e7df0bc7b2d8278a2c3ca0cf7a3f2f783d3c69800",
"d6a89e23fb22801a0d1186bf1bdd007e228f65a8aa9964d24d06cb5fbb0ce91c",
"eb8eff37f93af2faaba519f341decec3cecd3eeafcace32966db9723842c8a62",
"8b498a80a1b7af188c10c9abdf6aade81d14faaffcde2abcd6063baa673ebd12",
"539dde44014c850fe6eeb8b299eb7dae2e1f4bf83454b949e98aa73542cdc65a"
],
"threshold": 3
},
"timestamp": {
"keyids": [
"eb9799b483affac9da87ef4c9ea467928415c961349e607e5e6e485679b07f8f"
],
"threshold": 1,
"x-tuf-on-ci-expiry-period": 7,
"x-tuf-on-ci-signing-period": 6
}
},
"spec_version": "1.0.31",
"version": 1,
"x-tuf-on-ci-expiry-period": 240,
"x-tuf-on-ci-signing-period": 60
}
}
"threshold": 3
},
"snapshot": {
"keyids": [
"eb9799b483affac9da87ef4c9ea467928415c961349e607e5e6e485679b07f8f"
],
"threshold": 1,
"x-tuf-on-ci-expiry-period": 21,
"x-tuf-on-ci-signing-period": 7
},
"targets": {
"keyids": [
"a10513a5ab61acd0c6b6fbe0504856ead18f3b17c4fabbe3fa848c79a5a187cf",
"4f4d1dd75f2d7f3860e3a068d7bed90dec5f0faafcbe1ace7fb7d95d29e07228",
"88737ccdac7b49cc237e9aaead81be2a40278b886a693d8149a19cf543f093d3",
"d6a89e23fb22801a0d1186bf1bdd007e228f65a8aa9964d24d06cb5fbb0ce91c",
"eb8eff37f93af2faaba519f341decec3cecd3eeafcace32966db9723842c8a62",
"8b498a80a1b7af188c10c9abdf6aade81d14faaffcde2abcd6063baa673ebd12",
"539dde44014c850fe6eeb8b299eb7dae2e1f4bf83454b949e98aa73542cdc65a",
"54809115b40137aac01af4b7ac2408c77ea0d58fa4dad48fc3196497d2a26f44"
],
"threshold": 3
},
"timestamp": {
"keyids": [
"eb9799b483affac9da87ef4c9ea467928415c961349e607e5e6e485679b07f8f"
],
"threshold": 1,
"x-tuf-on-ci-expiry-period": 7,
"x-tuf-on-ci-signing-period": 6
}
},
"spec_version": "1.0.31",
"version": 3,
"x-tuf-on-ci-expiry-period": 240,
"x-tuf-on-ci-signing-period": 60
}
}

View file

@ -0,0 +1,28 @@
package verification
import (
"fmt"
"strings"
)
func VerifyCertExtensions(results []*AttestationProcessingResult, owner string, repo string) error {
for _, attestation := range results {
// TODO: handle proxima prefix
expectedSourceRepositoryOwnerURI := fmt.Sprintf("https://github.com/%s", owner)
sourceRepositoryOwnerURI := attestation.VerificationResult.Signature.Certificate.Extensions.SourceRepositoryOwnerURI
if !strings.EqualFold(expectedSourceRepositoryOwnerURI, sourceRepositoryOwnerURI) {
return fmt.Errorf("expected SourceRepositoryOwnerURI to be %s, got %s", expectedSourceRepositoryOwnerURI, sourceRepositoryOwnerURI)
}
// if repo is set, check the SourceRepositoryURI field
if repo != "" {
// TODO: handle proxima prefix
expectedSourceRepositoryURI := fmt.Sprintf("https://github.com/%s", repo)
sourceRepositoryURI := attestation.VerificationResult.Signature.Certificate.Extensions.SourceRepositoryURI
if !strings.EqualFold(expectedSourceRepositoryURI, sourceRepositoryURI) {
return fmt.Errorf("expected SourceRepositoryURI to be %s, got %s", expectedSourceRepositoryURI, sourceRepositoryURI)
}
}
}
return nil
}

View file

@ -0,0 +1,46 @@
package verification
import (
"testing"
"github.com/sigstore/sigstore-go/pkg/fulcio/certificate"
"github.com/sigstore/sigstore-go/pkg/verify"
"github.com/stretchr/testify/require"
)
func TestVerifyCertExtensions(t *testing.T) {
results := []*AttestationProcessingResult{
{
VerificationResult: &verify.VerificationResult{
Signature: &verify.SignatureVerificationResult{
Certificate: &certificate.Summary{
Extensions: certificate.Extensions{
SourceRepositoryOwnerURI: "https://github.com/owner",
SourceRepositoryURI: "https://github.com/owner/repo",
},
},
},
},
},
}
t.Run("VerifyCertExtensions with owner and repo", func(t *testing.T) {
err := VerifyCertExtensions(results, "owner", "owner/repo")
require.NoError(t, err)
})
t.Run("VerifyCertExtensions with owner", func(t *testing.T) {
err := VerifyCertExtensions(results, "owner", "")
require.NoError(t, err)
})
t.Run("VerifyCertExtensions with wrong owner", func(t *testing.T) {
err := VerifyCertExtensions(results, "wrong", "")
require.ErrorContains(t, err, "expected SourceRepositoryOwnerURI to be https://github.com/wrong, got https://github.com/owner")
})
t.Run("VerifyCertExtensions with wrong repo", func(t *testing.T) {
err := VerifyCertExtensions(results, "owner", "wrong")
require.ErrorContains(t, err, "expected SourceRepositoryURI to be https://github.com/wrong, got https://github.com/owner/repo")
})
}

View file

@ -31,7 +31,9 @@ func (v *MockSigstoreVerifier) Verify(attestations []*api.Attestation, policy ve
Signature: &verify.SignatureVerificationResult{
Certificate: &certificate.Summary{
Extensions: certificate.Extensions{
BuildSignerURI: "https://github.com/github/example/.github/workflows/release.yml@refs/heads/main",
BuildSignerURI: "https://github.com/github/example/.github/workflows/release.yml@refs/heads/main",
SourceRepositoryOwnerURI: "https://github.com/sigstore",
SourceRepositoryURI: "https://github.com/sigstore/sigstore-js",
},
},
},

View file

@ -56,6 +56,9 @@ func NewLiveSigstoreVerifier(config SigstoreConfig) *LiveSigstoreVerifier {
}
func (v *LiveSigstoreVerifier) chooseVerifier(b *bundle.ProtobufBundle) (*verify.SignedEntityVerifier, string, error) {
if !b.MinVersion("0.2") {
return nil, "", fmt.Errorf("unsupported bundle version: %s", b.MediaType)
}
verifyContent, err := b.VerificationContent()
if err != nil {
return nil, "", fmt.Errorf("failed to get bundle verification content: %v", err)

View file

@ -100,6 +100,19 @@ func TestLiveSigstoreVerifier(t *testing.T) {
require.Len(t, res.VerifyResults, 2)
require.NoError(t, res.Error)
})
t.Run("with invalid bundle version", func(t *testing.T) {
attestations := getAttestationsFor(t, "../test/data/sigstore-js-2.1.0-bundle-v0.1.json")
require.Len(t, attestations, 1)
verifier := NewLiveSigstoreVerifier(SigstoreConfig{
Logger: io.NewTestHandler(),
})
res := verifier.Verify(attestations, publicGoodPolicy(t))
require.Len(t, res.VerifyResults, 0)
require.ErrorContains(t, res.Error, "unsupported bundle version")
})
}
func publicGoodPolicy(t *testing.T) verify.PolicyBuilder {

View file

@ -70,7 +70,7 @@ func TestSetPolicyFlags(t *testing.T) {
opts.SetPolicyFlags()
require.Equal(t, "sigstore", opts.Owner)
require.Equal(t, "sigstore/sigstore-js", opts.Repo)
require.Equal(t, "^https://github.com/sigstore/sigstore-js/", opts.SANRegex)
require.Equal(t, "(?i)^https://github.com/sigstore/sigstore-js/", opts.SANRegex)
})
t.Run("does not set SANRegex when SANRegex and Repo are provided", func(t *testing.T) {
@ -99,7 +99,7 @@ func TestSetPolicyFlags(t *testing.T) {
opts.SetPolicyFlags()
require.Equal(t, "sigstore", opts.Owner)
require.Equal(t, "^https://github.com/sigstore/", opts.SANRegex)
require.Equal(t, "(?i)^https://github.com/sigstore/", opts.SANRegex)
})
t.Run("does not set SANRegex when SANRegex and Owner are provided", func(t *testing.T) {

View file

@ -21,7 +21,8 @@ const (
)
func expandToGitHubURL(ownerOrRepo string) string {
return fmt.Sprintf("^https://github.com/%s/", ownerOrRepo)
// TODO: handle proxima prefix
return fmt.Sprintf("(?i)^https://github.com/%s/", ownerOrRepo)
}
func buildSANMatcher(opts *Options) (verify.SubjectAlternativeNameMatcher, error) {
@ -42,19 +43,6 @@ func buildSANMatcher(opts *Options) (verify.SubjectAlternativeNameMatcher, error
return verify.SubjectAlternativeNameMatcher{}, nil
}
func buildCertExtensions(opts *Options, runnerEnv string) certificate.Extensions {
extensions := certificate.Extensions{
SourceRepositoryOwnerURI: fmt.Sprintf("https://github.com/%s", opts.Owner),
RunnerEnvironment: runnerEnv,
}
// if opts.Repo is set, set the SourceRepositoryURI field before returning the extensions
if opts.Repo != "" {
extensions.SourceRepositoryURI = fmt.Sprintf("https://github.com/%s", opts.Repo)
}
return extensions
}
func buildCertificateIdentityOption(opts *Options, runnerEnv string) (verify.PolicyOption, error) {
sanMatcher, err := buildSANMatcher(opts)
if err != nil {
@ -66,7 +54,9 @@ func buildCertificateIdentityOption(opts *Options, runnerEnv string) (verify.Pol
return nil, err
}
extensions := buildCertExtensions(opts, runnerEnv)
extensions := certificate.Extensions{
RunnerEnvironment: runnerEnv,
}
certId, err := verify.NewCertificateIdentity(sanMatcher, issuerMatcher, extensions)
if err != nil {

View file

@ -235,6 +235,12 @@ func runVerify(opts *Options) error {
return sigstoreRes.Error
}
// Verify extensions
if err := verification.VerifyCertExtensions(sigstoreRes.VerifyResults, opts.Owner, opts.Repo); err != nil {
opts.Logger.Println(opts.Logger.ColorScheme.Red("✗ Verification failed"))
return err
}
opts.Logger.Println(opts.Logger.ColorScheme.Green("✓ Verification succeeded!\n"))
// If an exporter is provided with the --json flag, write the results to the terminal in JSON format

View file

@ -60,7 +60,7 @@ func TestVerifyIntegration(t *testing.T) {
err := runVerify(&opts)
require.Error(t, err)
require.ErrorContains(t, err, "verifying with issuer \"sigstore.dev\": failed to verify certificate identity: no matching CertificateIdentity found, last error: expected SourceRepositoryURI to be \"https://github.com/sigstore/fakerepo\", got \"https://github.com/sigstore/sigstore-js\"")
require.ErrorContains(t, err, "expected SourceRepositoryURI to be https://github.com/sigstore/fakerepo, got https://github.com/sigstore/sigstore-js")
})
t.Run("with invalid owner", func(t *testing.T) {
@ -69,7 +69,7 @@ func TestVerifyIntegration(t *testing.T) {
err := runVerify(&opts)
require.Error(t, err)
require.ErrorContains(t, err, "verifying with issuer \"sigstore.dev\": failed to verify certificate identity: no matching CertificateIdentity found, last error: expected SourceRepositoryOwnerURI to be \"https://github.com/fakeowner\", got \"https://github.com/sigstore\"")
require.ErrorContains(t, err, "expected SourceRepositoryOwnerURI to be https://github.com/fakeowner, got https://github.com/sigstore")
})
t.Run("with invalid owner and invalid repo", func(t *testing.T) {
@ -78,7 +78,7 @@ func TestVerifyIntegration(t *testing.T) {
err := runVerify(&opts)
require.Error(t, err)
require.ErrorContains(t, err, "verifying with issuer \"sigstore.dev\": failed to verify certificate identity: no matching CertificateIdentity found, last error: expected SourceRepositoryURI to be \"https://github.com/fakeowner/fakerepo\"")
require.ErrorContains(t, err, "expected SourceRepositoryURI to be https://github.com/fakeowner/fakerepo, got https://github.com/sigstore/sigstore-js")
})
}

View file

@ -76,7 +76,7 @@ func TestNewVerifyCmd(t *testing.T) {
Limit: 30,
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
SANRegex: "^https://github.com/sigstore/",
SANRegex: "(?i)^https://github.com/sigstore/",
SigstoreVerifier: verification.NewMockSigstoreVerifier(t),
},
wantsErr: false,
@ -91,7 +91,7 @@ func TestNewVerifyCmd(t *testing.T) {
Limit: 30,
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
SANRegex: "^https://github.com/sigstore/",
SANRegex: "(?i)^https://github.com/sigstore/",
SigstoreVerifier: verification.NewMockSigstoreVerifier(t),
},
wantsErr: false,
@ -105,7 +105,7 @@ func TestNewVerifyCmd(t *testing.T) {
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
Limit: 30,
SANRegex: "^https://github.com/sigstore/",
SANRegex: "(?i)^https://github.com/sigstore/",
SigstoreVerifier: verification.NewMockSigstoreVerifier(t),
},
wantsErr: true,
@ -133,7 +133,7 @@ func TestNewVerifyCmd(t *testing.T) {
Limit: 30,
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
SANRegex: "^https://github.com/sigstore/",
SANRegex: "(?i)^https://github.com/sigstore/",
SigstoreVerifier: verification.NewMockSigstoreVerifier(t),
},
wantsErr: false,
@ -147,7 +147,7 @@ func TestNewVerifyCmd(t *testing.T) {
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
Limit: 101,
SANRegex: "^https://github.com/sigstore/",
SANRegex: "(?i)^https://github.com/sigstore/",
SigstoreVerifier: verification.NewMockSigstoreVerifier(t),
},
wantsErr: false,
@ -161,7 +161,7 @@ func TestNewVerifyCmd(t *testing.T) {
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
Limit: 0,
SANRegex: "^https://github.com/sigstore/",
SANRegex: "(?i)^https://github.com/sigstore/",
SigstoreVerifier: verification.NewMockSigstoreVerifier(t),
},
wantsErr: true,
@ -176,7 +176,7 @@ func TestNewVerifyCmd(t *testing.T) {
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
SAN: "https://github.com/sigstore/",
SANRegex: "^https://github.com/sigstore/",
SANRegex: "(?i)^https://github.com/sigstore/",
SigstoreVerifier: verification.NewMockSigstoreVerifier(t),
},
wantsErr: true,
@ -191,7 +191,7 @@ func TestNewVerifyCmd(t *testing.T) {
Limit: 30,
OIDCIssuer: GitHubOIDCIssuer,
Owner: "sigstore",
SANRegex: "^https://github.com/sigstore/",
SANRegex: "(?i)^https://github.com/sigstore/",
SigstoreVerifier: verification.NewMockSigstoreVerifier(t),
},
wantsExporter: true,
@ -340,14 +340,32 @@ func TestRunVerify(t *testing.T) {
require.Nil(t, runVerify(&opts))
})
t.Run("with owner which not matches SourceRepositoryOwnerURI", func(t *testing.T) {
opts := publicGoodOpts
opts.BundlePath = ""
opts.Owner = "owner"
err := runVerify(&opts)
require.ErrorContains(t, err, "expected SourceRepositoryOwnerURI to be https://github.com/owner, got https://github.com/sigstore")
})
t.Run("with repo", func(t *testing.T) {
opts := publicGoodOpts
opts.BundlePath = ""
opts.Repo = "github/example"
opts.Repo = "sigstore/sigstore-js"
require.Nil(t, runVerify(&opts))
})
t.Run("with repo which not matches SourceRepositoryURI", func(t *testing.T) {
opts := publicGoodOpts
opts.BundlePath = ""
opts.Repo = "wrong/example"
err := runVerify(&opts)
require.ErrorContains(t, err, "expected SourceRepositoryURI to be https://github.com/wrong/example, got https://github.com/sigstore/sigstore-js")
})
t.Run("with invalid repo", func(t *testing.T) {
opts := publicGoodOpts
opts.BundlePath = ""

View file

@ -60,7 +60,7 @@ func newSSHCmd(app *App) *cobra.Command {
The %[1]sssh%[1]s command will automatically create a public/private ssh key pair in the
%[1]s~/.ssh%[1]s directory if you do not have an existing valid key pair. When selecting the
key pair to use, the preferred order is:
1. Key specified by %[1]s-i%[1]s in %[1]s<ssh-flags>%[1]s
2. Automatic key, if it already exists
3. First valid key pair in ssh config (according to %[1]sssh -G%[1]s)

View file

@ -5,10 +5,15 @@ on:
- "v*"
permissions:
contents: write
id-token: write
attestations: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: cli/gh-extension-precompile@v1
with:
generate_attestations: true
go_version_file: go.mod

View file

@ -10,7 +10,7 @@ jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: cli/gh-extension-precompile@v1
with:
build_script_override: "script/build.sh"

View file

@ -81,19 +81,11 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
opts.BaseRepo = f.BaseRepo
opts.HasRepoOverride = cmd.Flags().Changed("repo")
if err := cmdutil.MutuallyExclusive(
"specify only one of `--editor` or `--web`",
opts.EditorMode,
opts.WebMode,
); err != nil {
return err
}
config, err := f.Config()
var err error
opts.EditorMode, err = prShared.InitEditorMode(f, opts.EditorMode, opts.WebMode, opts.IO.CanPrompt())
if err != nil {
return err
}
opts.EditorMode = !opts.WebMode && (opts.EditorMode || config.PreferEditorPrompt("").Value == "enabled")
titleProvided := cmd.Flags().Changed("title")
bodyProvided := cmd.Flags().Changed("body")
@ -119,9 +111,6 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
if opts.Interactive && !opts.IO.CanPrompt() {
return cmdutil.FlagErrorf("must provide `--title` and `--body` when not running interactively")
}
if opts.EditorMode && !opts.IO.CanPrompt() {
return errors.New("--editor or enabled prefer_editor_prompt configuration are not supported in non-tty mode")
}
if runF != nil {
return runF(opts)
@ -133,11 +122,11 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
cmd.Flags().StringVarP(&opts.Title, "title", "t", "", "Supply a title. Will prompt for one otherwise.")
cmd.Flags().StringVarP(&opts.Body, "body", "b", "", "Supply a body. Will prompt for one otherwise.")
cmd.Flags().StringVarP(&bodyFile, "body-file", "F", "", "Read body text from `file` (use \"-\" to read from standard input)")
cmd.Flags().BoolVarP(&opts.EditorMode, "editor", "e", false, "Skip prompts and open the text editor to write the title and body in. The first line is the title and the rest text is the body.")
cmd.Flags().BoolVarP(&opts.EditorMode, "editor", "e", false, "Skip prompts and open the text editor to write the title and body in. The first line is the title and the remaining text is the body.")
cmd.Flags().BoolVarP(&opts.WebMode, "web", "w", false, "Open the browser to create an issue")
cmd.Flags().StringSliceVarP(&opts.Assignees, "assignee", "a", nil, "Assign people by their `login`. Use \"@me\" to self-assign.")
cmd.Flags().StringSliceVarP(&opts.Labels, "label", "l", nil, "Add labels by `name`")
cmd.Flags().StringSliceVarP(&opts.Projects, "project", "p", nil, "Add the issue to projects by `name`")
cmd.Flags().StringSliceVarP(&opts.Projects, "project", "p", nil, "Add the issue to projects by `title`")
cmd.Flags().StringVarP(&opts.Milestone, "milestone", "m", "", "Add the issue to a milestone by `name`")
cmd.Flags().StringVar(&opts.RecoverFile, "recover", "", "Recover input from a failed run of create")
cmd.Flags().StringVarP(&opts.Template, "template", "T", "", "Template `file` to use as starting body text")

View file

@ -46,6 +46,7 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
}
var bodyFile string
var removeMilestone bool
cmd := &cobra.Command{
Use: "edit {<numbers> | <urls>}",
@ -62,6 +63,7 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
$ gh issue edit 23 --add-assignee "@me" --remove-assignee monalisa,hubot
$ gh issue edit 23 --add-project "Roadmap" --remove-project v1,v2
$ gh issue edit 23 --milestone "Version 1"
$ gh issue edit 23 --remove-milestone
$ gh issue edit 23 --body-file body.txt
$ gh issue edit 23 34 --add-label "help wanted"
`),
@ -95,6 +97,14 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
}
}
if err := cmdutil.MutuallyExclusive(
"specify only one of `--milestone` or `--remove-milestone`",
flags.Changed("milestone"),
removeMilestone,
); err != nil {
return err
}
if flags.Changed("title") {
opts.Editable.Title.Edited = true
}
@ -107,8 +117,13 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
if flags.Changed("add-project") || flags.Changed("remove-project") {
opts.Editable.Projects.Edited = true
}
if flags.Changed("milestone") {
if flags.Changed("milestone") || removeMilestone {
opts.Editable.Milestone.Edited = true
// Note that when `--remove-milestone` is provided, the value of
// `opts.Editable.Milestone.Value` will automatically be empty,
// which results in milestone association removal. For reference,
// see the `Editable.MilestoneId` method.
}
if !opts.Editable.Dirty() {
@ -138,9 +153,10 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
cmd.Flags().StringSliceVar(&opts.Editable.Assignees.Remove, "remove-assignee", nil, "Remove assigned users by their `login`. Use \"@me\" to unassign yourself.")
cmd.Flags().StringSliceVar(&opts.Editable.Labels.Add, "add-label", nil, "Add labels by `name`")
cmd.Flags().StringSliceVar(&opts.Editable.Labels.Remove, "remove-label", nil, "Remove labels by `name`")
cmd.Flags().StringSliceVar(&opts.Editable.Projects.Add, "add-project", nil, "Add the issue to projects by `name`")
cmd.Flags().StringSliceVar(&opts.Editable.Projects.Remove, "remove-project", nil, "Remove the issue from projects by `name`")
cmd.Flags().StringSliceVar(&opts.Editable.Projects.Add, "add-project", nil, "Add the issue to projects by `title`")
cmd.Flags().StringSliceVar(&opts.Editable.Projects.Remove, "remove-project", nil, "Remove the issue from projects by `title`")
cmd.Flags().StringVarP(&opts.Editable.Milestone.Value, "milestone", "m", "", "Edit the milestone the issue belongs to by `name`")
cmd.Flags().BoolVar(&removeMilestone, "remove-milestone", false, "Remove the milestone association from the issue")
return cmd
}

View file

@ -104,6 +104,11 @@ func TestNewCmdEdit(t *testing.T) {
},
wantsErr: false,
},
{
name: "both body and body-file flags",
input: "23 --body foo --body-file bar",
wantsErr: true,
},
{
name: "add-assignee flag",
input: "23 --add-assignee monalisa,hubot",
@ -206,6 +211,25 @@ func TestNewCmdEdit(t *testing.T) {
},
wantsErr: false,
},
{
name: "remove-milestone flag",
input: "23 --remove-milestone",
output: EditOptions{
SelectorArgs: []string{"23"},
Editable: prShared.Editable{
Milestone: prShared.EditableString{
Value: "",
Edited: true,
},
},
},
wantsErr: false,
},
{
name: "both milestone and remove-milestone flags",
input: "23 --milestone foo --remove-milestone",
wantsErr: true,
},
{
name: "add label to multiple issues",
input: "23 34 --add-label bug",
@ -221,17 +245,8 @@ func TestNewCmdEdit(t *testing.T) {
wantsErr: false,
},
{
name: "interactive multiple issues",
input: "23 34",
output: EditOptions{
SelectorArgs: []string{"23", "34"},
Editable: prShared.Editable{
Labels: prShared.EditableSlice{
Add: []string{"bug"},
Edited: true,
},
},
},
name: "interactive multiple issues",
input: "23 34",
wantsErr: true,
},
}

View file

@ -66,6 +66,9 @@ func NewCmdChecks(f *cmdutil.Factory, runF func(*ChecksOptions) error) *cobra.Co
Without an argument, the pull request that belongs to the current branch
is selected.
Additional exit codes:
8: Checks pending
`),
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {

View file

@ -30,15 +30,16 @@ import (
type CreateOptions struct {
// This struct stores user input and factory functions
HttpClient func() (*http.Client, error)
GitClient *git.Client
Config func() (gh.Config, error)
IO *iostreams.IOStreams
Remotes func() (ghContext.Remotes, error)
Branch func() (string, error)
Browser browser.Browser
Prompter shared.Prompt
Finder shared.PRFinder
HttpClient func() (*http.Client, error)
GitClient *git.Client
Config func() (gh.Config, error)
IO *iostreams.IOStreams
Remotes func() (ghContext.Remotes, error)
Branch func() (string, error)
Browser browser.Browser
Prompter shared.Prompt
Finder shared.PRFinder
TitledEditSurvey func(string, string) (string, string, error)
TitleProvided bool
BodyProvided bool
@ -49,6 +50,7 @@ type CreateOptions struct {
Autofill bool
FillVerbose bool
FillFirst bool
EditorMode bool
WebMode bool
RecoverFile string
@ -88,14 +90,15 @@ type CreateContext struct {
func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Command {
opts := &CreateOptions{
IO: f.IOStreams,
HttpClient: f.HttpClient,
GitClient: f.GitClient,
Config: f.Config,
Remotes: f.Remotes,
Branch: f.Branch,
Browser: f.Browser,
Prompter: f.Prompter,
IO: f.IOStreams,
HttpClient: f.HttpClient,
GitClient: f.GitClient,
Config: f.Config,
Remotes: f.Remotes,
Branch: f.Branch,
Browser: f.Browser,
Prompter: f.Prompter,
TitledEditSurvey: shared.TitledEditSurvey(&shared.UserEditor{Config: f.Config, IO: f.IOStreams}),
}
var bodyFile string
@ -177,6 +180,20 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
return cmdutil.FlagErrorf("`--fill-verbose` is not supported with `--fill`")
}
if err := cmdutil.MutuallyExclusive(
"specify only one of `--editor` or `--web`",
opts.EditorMode,
opts.WebMode,
); err != nil {
return err
}
var err error
opts.EditorMode, err = shared.InitEditorMode(f, opts.EditorMode, opts.WebMode, opts.IO.CanPrompt())
if err != nil {
return err
}
opts.BodyProvided = cmd.Flags().Changed("body")
if bodyFile != "" {
b, err := cmdutil.ReadFile(bodyFile, opts.IO.In)
@ -213,6 +230,7 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
fl.StringVarP(&bodyFile, "body-file", "F", "", "Read body text from `file` (use \"-\" to read from standard input)")
fl.StringVarP(&opts.BaseBranch, "base", "B", "", "The `branch` into which you want your code merged")
fl.StringVarP(&opts.HeadBranch, "head", "H", "", "The `branch` that contains commits for your pull request (default [current branch])")
fl.BoolVarP(&opts.EditorMode, "editor", "e", false, "Skip prompts and open the text editor to write the title and body in. The first line is the title and the remaining text is the body.")
fl.BoolVarP(&opts.WebMode, "web", "w", false, "Open the web browser to create a pull request")
fl.BoolVarP(&opts.FillVerbose, "fill-verbose", "", false, "Use commits msg+body for description")
fl.BoolVarP(&opts.Autofill, "fill", "f", false, "Use commit info for title and body")
@ -220,7 +238,7 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
fl.StringSliceVarP(&opts.Reviewers, "reviewer", "r", nil, "Request reviews from people or teams by their `handle`")
fl.StringSliceVarP(&opts.Assignees, "assignee", "a", nil, "Assign people by their `login`. Use \"@me\" to self-assign.")
fl.StringSliceVarP(&opts.Labels, "label", "l", nil, "Add labels by `name`")
fl.StringSliceVarP(&opts.Projects, "project", "p", nil, "Add the pull request to projects by `name`")
fl.StringSliceVarP(&opts.Projects, "project", "p", nil, "Add the pull request to projects by `title`")
fl.StringVarP(&opts.Milestone, "milestone", "m", "", "Add the pull request to a milestone by `name`")
fl.Bool("no-maintainer-edit", false, "Disable maintainer's ability to modify pull request")
fl.StringVar(&opts.RecoverFile, "recover", "", "Recover input from a failed run of create")
@ -315,7 +333,7 @@ func createRun(opts *CreateOptions) (err error) {
ghrepo.FullName(ctx.BaseRepo))
}
if opts.FillVerbose || opts.Autofill || opts.FillFirst || (opts.TitleProvided && opts.BodyProvided) {
if !opts.EditorMode && (opts.FillVerbose || opts.Autofill || opts.FillFirst || (opts.TitleProvided && opts.BodyProvided)) {
err = handlePush(*opts, *ctx)
if err != nil {
return
@ -330,71 +348,101 @@ func createRun(opts *CreateOptions) (err error) {
}
}
if !opts.TitleProvided {
err = shared.TitleSurvey(opts.Prompter, state)
if err != nil {
return
}
action := shared.SubmitAction
if opts.IsDraft {
action = shared.SubmitDraftAction
}
defer shared.PreserveInput(opts.IO, state, &err)()
tpl := shared.NewTemplateManager(client.HTTP(), ctx.BaseRepo, opts.Prompter, opts.RootDirOverride, opts.RepoOverride == "", true)
if !opts.BodyProvided {
templateContent := ""
if opts.RecoverFile == "" {
tpl := shared.NewTemplateManager(client.HTTP(), ctx.BaseRepo, opts.Prompter, opts.RootDirOverride, opts.RepoOverride == "", true)
if opts.EditorMode {
if opts.Template != "" {
var template shared.Template
if opts.Template != "" {
template, err = tpl.Select(opts.Template)
if err != nil {
return
}
} else {
template, err = tpl.Choose()
if err != nil {
return
}
template, err = tpl.Select(opts.Template)
if err != nil {
return
}
if state.Title == "" {
state.Title = template.Title()
}
state.Body = string(template.Body())
}
if template != nil {
templateContent = string(template.Body())
state.Title, state.Body, err = opts.TitledEditSurvey(state.Title, state.Body)
if err != nil {
return
}
if state.Title == "" {
err = fmt.Errorf("title can't be blank")
return
}
} else {
if !opts.TitleProvided {
err = shared.TitleSurvey(opts.Prompter, state)
if err != nil {
return
}
}
err = shared.BodySurvey(opts.Prompter, state, templateContent)
if err != nil {
return
defer shared.PreserveInput(opts.IO, state, &err)()
if !opts.BodyProvided {
templateContent := ""
if opts.RecoverFile == "" {
var template shared.Template
if opts.Template != "" {
template, err = tpl.Select(opts.Template)
if err != nil {
return
}
} else {
template, err = tpl.Choose()
if err != nil {
return
}
}
if template != nil {
templateContent = string(template.Body())
}
}
err = shared.BodySurvey(opts.Prompter, state, templateContent)
if err != nil {
return
}
}
}
openURL, err = generateCompareURL(*ctx, *state)
if err != nil {
return
}
allowPreview := !state.HasMetadata() && shared.ValidURL(openURL) && !opts.DryRun
allowMetadata := ctx.BaseRepo.ViewerCanTriage()
action, err := shared.ConfirmPRSubmission(opts.Prompter, allowPreview, allowMetadata, state.Draft)
if err != nil {
return fmt.Errorf("unable to confirm: %w", err)
}
if action == shared.MetadataAction {
fetcher := &shared.MetadataFetcher{
IO: opts.IO,
APIClient: client,
Repo: ctx.BaseRepo,
State: state,
}
err = shared.MetadataSurvey(opts.Prompter, opts.IO, ctx.BaseRepo, fetcher, state)
openURL, err = generateCompareURL(*ctx, *state)
if err != nil {
return
}
action, err = shared.ConfirmPRSubmission(opts.Prompter, !state.HasMetadata() && !opts.DryRun, false, state.Draft)
allowPreview := !state.HasMetadata() && shared.ValidURL(openURL) && !opts.DryRun
allowMetadata := ctx.BaseRepo.ViewerCanTriage()
action, err = shared.ConfirmPRSubmission(opts.Prompter, allowPreview, allowMetadata, state.Draft)
if err != nil {
return
return fmt.Errorf("unable to confirm: %w", err)
}
if action == shared.MetadataAction {
fetcher := &shared.MetadataFetcher{
IO: opts.IO,
APIClient: client,
Repo: ctx.BaseRepo,
State: state,
}
err = shared.MetadataSurvey(opts.Prompter, opts.IO, ctx.BaseRepo, fetcher, state)
if err != nil {
return
}
action, err = shared.ConfirmPRSubmission(opts.Prompter, !state.HasMetadata() && !opts.DryRun, false, state.Draft)
if err != nil {
return
}
}
}

View file

@ -40,6 +40,7 @@ func TestNewCmdCreate(t *testing.T) {
tty bool
stdin string
cli string
config string
wantsErr bool
wantsOpts CreateOptions
}{
@ -202,6 +203,64 @@ func TestNewCmdCreate(t *testing.T) {
cli: "--web --dry-run",
wantsErr: true,
},
{
name: "editor by cli",
tty: true,
cli: "--editor",
wantsErr: false,
wantsOpts: CreateOptions{
Title: "",
Body: "",
RecoverFile: "",
WebMode: false,
EditorMode: true,
MaintainerCanModify: true,
},
},
{
name: "editor by config",
tty: true,
cli: "",
config: "prefer_editor_prompt: enabled",
wantsErr: false,
wantsOpts: CreateOptions{
Title: "",
Body: "",
RecoverFile: "",
WebMode: false,
EditorMode: true,
MaintainerCanModify: true,
},
},
{
name: "editor and web",
tty: true,
cli: "--editor --web",
wantsErr: true,
},
{
name: "can use web even though editor is enabled by config",
tty: true,
cli: `--web --title mytitle --body "issue body"`,
config: "prefer_editor_prompt: enabled",
wantsErr: false,
wantsOpts: CreateOptions{
Title: "mytitle",
Body: "issue body",
TitleProvided: true,
BodyProvided: true,
RecoverFile: "",
WebMode: true,
EditorMode: false,
MaintainerCanModify: true,
},
},
{
name: "editor with non-tty",
tty: false,
cli: "--editor",
wantsErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@ -215,6 +274,12 @@ func TestNewCmdCreate(t *testing.T) {
f := &cmdutil.Factory{
IOStreams: ios,
Config: func() (gh.Config, error) {
if tt.config != "" {
return config.NewFromString(tt.config), nil
}
return config.NewBlankConfig(), nil
},
}
var opts *CreateOptions
@ -1372,6 +1437,33 @@ func Test_createRun(t *testing.T) {
expectedOut: "https://github.com/OWNER/REPO/pull/12\n",
expectedErrOut: "\nCreating pull request for feature into master in OWNER/REPO\n\n",
},
{
name: "editor",
httpStubs: func(r *httpmock.Registry, t *testing.T) {
r.Register(
httpmock.GraphQL(`mutation PullRequestCreate\b`),
httpmock.GraphQLMutation(`
{
"data": { "createPullRequest": { "pullRequest": {
"URL": "https://github.com/OWNER/REPO/pull/12"
} } }
}
`, func(inputs map[string]interface{}) {
assert.Equal(t, "title", inputs["title"])
assert.Equal(t, "body", inputs["body"])
}))
},
setup: func(opts *CreateOptions, t *testing.T) func() {
opts.EditorMode = true
opts.HeadBranch = "feature"
opts.TitledEditSurvey = func(string, string) (string, string, error) { return "title", "body", nil }
return func() {}
},
cmdStubs: func(cs *run.CommandStubber) {
cs.Register("git -c log.ShowSignature=false log --pretty=format:%H%x00%s%x00%b%x00 --cherry origin/master...feature", 0, "")
},
expectedOut: "https://github.com/OWNER/REPO/pull/12\n",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View file

@ -43,6 +43,7 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
}
var bodyFile string
var removeMilestone bool
cmd := &cobra.Command{
Use: "edit [<number> | <url> | <branch>]",
@ -63,6 +64,7 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
$ gh pr edit 23 --add-assignee "@me" --remove-assignee monalisa,hubot
$ gh pr edit 23 --add-project "Roadmap" --remove-project v1,v2
$ gh pr edit 23 --milestone "Version 1"
$ gh pr edit 23 --remove-milestone
`),
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
@ -95,6 +97,14 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
}
}
if err := cmdutil.MutuallyExclusive(
"specify only one of `--milestone` or `--remove-milestone`",
flags.Changed("milestone"),
removeMilestone,
); err != nil {
return err
}
if flags.Changed("title") {
opts.Editable.Title.Edited = true
}
@ -116,8 +126,13 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
if flags.Changed("add-project") || flags.Changed("remove-project") {
opts.Editable.Projects.Edited = true
}
if flags.Changed("milestone") {
if flags.Changed("milestone") || removeMilestone {
opts.Editable.Milestone.Edited = true
// Note that when `--remove-milestone` is provided, the value of
// `opts.Editable.Milestone.Value` will automatically be empty,
// which results in milestone association removal. For reference,
// see the `Editable.MilestoneId` method.
}
if !opts.Editable.Dirty() {
@ -146,9 +161,10 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
cmd.Flags().StringSliceVar(&opts.Editable.Assignees.Remove, "remove-assignee", nil, "Remove assigned users by their `login`. Use \"@me\" to unassign yourself.")
cmd.Flags().StringSliceVar(&opts.Editable.Labels.Add, "add-label", nil, "Add labels by `name`")
cmd.Flags().StringSliceVar(&opts.Editable.Labels.Remove, "remove-label", nil, "Remove labels by `name`")
cmd.Flags().StringSliceVar(&opts.Editable.Projects.Add, "add-project", nil, "Add the pull request to projects by `name`")
cmd.Flags().StringSliceVar(&opts.Editable.Projects.Remove, "remove-project", nil, "Remove the pull request from projects by `name`")
cmd.Flags().StringSliceVar(&opts.Editable.Projects.Add, "add-project", nil, "Add the pull request to projects by `title`")
cmd.Flags().StringSliceVar(&opts.Editable.Projects.Remove, "remove-project", nil, "Remove the pull request from projects by `title`")
cmd.Flags().StringVarP(&opts.Editable.Milestone.Value, "milestone", "m", "", "Edit the milestone the pull request belongs to by `name`")
cmd.Flags().BoolVar(&removeMilestone, "remove-milestone", false, "Remove the milestone association from the pull request")
_ = cmdutil.RegisterBranchCompletionFlags(f.GitClient, cmd, "base")

View file

@ -112,6 +112,11 @@ func TestNewCmdEdit(t *testing.T) {
},
wantsErr: false,
},
{
name: "both body and body-file flags",
input: "23 --body foo --body-file bar",
wantsErr: true,
},
{
name: "base flag",
input: "23 --base base-branch-name",
@ -256,6 +261,25 @@ func TestNewCmdEdit(t *testing.T) {
},
wantsErr: false,
},
{
name: "remove-milestone flag",
input: "23 --remove-milestone",
output: EditOptions{
SelectorArg: "23",
Editable: shared.Editable{
Milestone: shared.EditableString{
Value: "",
Edited: true,
},
},
},
wantsErr: false,
},
{
name: "both milestone and remove-milestone flags",
input: "23 --milestone foo --remove-milestone",
wantsErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View file

@ -72,7 +72,7 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
Find a PR that introduced a given commit
$ gh pr list --search "<SHA>" --state merged
`),
`),
Aliases: []string{"ls"},
Args: cmdutil.NoArgsQuoteReminder,
RunE: func(cmd *cobra.Command, args []string) error {

View file

@ -88,7 +88,7 @@ func NewCmdMerge(f *cmdutil.Factory, runF func(*MergeOptions) error) *cobra.Comm
If required checks have not yet passed, auto-merge will be enabled.
If required checks have passed, the pull request will be added to the merge queue.
To bypass a merge queue and merge directly, pass the %[1]s--admin%[1]s flag.
`, "`"),
`, "`"),
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.Finder = shared.NewFinder(f)

View file

@ -1,6 +1,7 @@
package shared
import (
"errors"
"fmt"
"strings"
@ -357,3 +358,26 @@ func TitledEditSurvey(editor Editor) func(string, string) (string, string, error
return title, strings.TrimSuffix(body, "\n"), nil
}
}
func InitEditorMode(f *cmdutil.Factory, editorMode bool, webMode bool, canPrompt bool) (bool, error) {
if err := cmdutil.MutuallyExclusive(
"specify only one of `--editor` or `--web`",
editorMode,
webMode,
); err != nil {
return false, err
}
config, err := f.Config()
if err != nil {
return false, err
}
editorMode = !webMode && (editorMode || config.PreferEditorPrompt("").Value == "enabled")
if editorMode && !canPrompt {
return false, errors.New("--editor or enabled prefer_editor_prompt configuration are not supported in non-tty mode")
}
return editorMode, nil
}

View file

@ -101,23 +101,23 @@ func pullRequestStatus(httpClient *http.Client, repo ghrepo.Interface, options r
}
query := fragments + queryPrefix + `
viewerCreated: search(query: $viewerQuery, type: ISSUE, first: $per_page) {
totalCount: issueCount
edges {
node {
...prWithReviews
}
}
}
reviewRequested: search(query: $reviewerQuery, type: ISSUE, first: $per_page) {
totalCount: issueCount
edges {
node {
...pr
}
}
}
}
viewerCreated: search(query: $viewerQuery, type: ISSUE, first: $per_page) {
totalCount: issueCount
edges {
node {
...prWithReviews
}
}
}
reviewRequested: search(query: $reviewerQuery, type: ISSUE, first: $per_page) {
totalCount: issueCount
edges {
node {
...pr
}
}
}
}
`
currentUsername := options.Username

View file

@ -115,7 +115,10 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
Use release notes from a file
$ gh release create v1.2.3 -F changelog.md
Use annotated tag notes
$ gh release create v1.2.3 --notes-from-tag
Don't mark the release as latest
$ gh release create v1.2.3 --latest=false
@ -516,12 +519,38 @@ func createRun(opts *CreateOptions) error {
}
func gitTagInfo(client *git.Client, tagName string) (string, error) {
cmd, err := client.Command(context.Background(), "tag", "--list", tagName, "--format=%(contents:subject)%0a%0a%(contents:body)")
contentCmd, err := client.Command(context.Background(), "tag", "--list", tagName, "--format=%(contents)")
if err != nil {
return "", err
}
b, err := cmd.Output()
return string(b), err
content, err := contentCmd.Output()
if err != nil {
return "", err
}
// If there is a signature, we should strip it from the end of the content.
// Note that, we can achieve this by looking for markers like "-----BEGIN PGP
// SIGNATURE-----" and cut the remaining text from the content, but this is
// not a safe approach, because, although unlikely, the content can contain
// a signature-like section which we shouldn't leave it as is. So, we need
// to get the tag signature as a whole, if any, and remote it from the content.
signatureCmd, err := client.Command(context.Background(), "tag", "--list", tagName, "--format=%(contents:signature)")
if err != nil {
return "", err
}
signature, err := signatureCmd.Output()
if err != nil {
return "", err
}
if len(signature) == 0 {
// The tag annotation content has no trailing signature to strip out,
// so we return the entire content.
return string(content), nil
}
body, _ := strings.CutSuffix(string(content), "\n"+string(signature))
return body, nil
}
func detectPreviousTag(client *git.Client, headRef string) (string, error) {

View file

@ -412,6 +412,14 @@ func Test_NewCmdCreate(t *testing.T) {
}
func Test_createRun(t *testing.T) {
const contentCmd = `git tag --list .* --format=%\(contents\)`
const signatureCmd = `git tag --list .* --format=%\(contents:signature\)`
defaultRunStubs := func(rs *run.CommandStubber) {
rs.Register(contentCmd, 0, "")
rs.Register(signatureCmd, 0, "")
}
tests := []struct {
name string
isTTY bool
@ -432,9 +440,7 @@ func Test_createRun(t *testing.T) {
BodyProvided: true,
Target: "",
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.RESTPayload(201, `{
"url": "https://api.github.com/releases/123",
@ -464,9 +470,7 @@ func Test_createRun(t *testing.T) {
Target: "",
DiscussionCategory: "General",
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.RESTPayload(201, `{
"url": "https://api.github.com/releases/123",
@ -496,9 +500,7 @@ func Test_createRun(t *testing.T) {
BodyProvided: true,
Target: "main",
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.RESTPayload(201, `{
"url": "https://api.github.com/releases/123",
@ -527,9 +529,7 @@ func Test_createRun(t *testing.T) {
Draft: true,
Target: "",
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.RESTPayload(201, `{
"url": "https://api.github.com/releases/123",
@ -558,9 +558,7 @@ func Test_createRun(t *testing.T) {
BodyProvided: true,
GenerateNotes: false,
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.RESTPayload(201, `{
"url": "https://api.github.com/releases/123",
@ -589,9 +587,7 @@ func Test_createRun(t *testing.T) {
BodyProvided: true,
GenerateNotes: true,
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.RESTPayload(201, `{
"url": "https://api.github.com/releases/123",
@ -621,9 +617,7 @@ func Test_createRun(t *testing.T) {
GenerateNotes: true,
NotesStartTag: "v1.1.0",
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases/generate-notes"),
httpmock.RESTPayload(200, `{
@ -664,9 +658,7 @@ func Test_createRun(t *testing.T) {
GenerateNotes: true,
NotesStartTag: "v1.1.0",
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases/generate-notes"),
httpmock.RESTPayload(200, `{
@ -715,9 +707,7 @@ func Test_createRun(t *testing.T) {
},
Concurrency: 1,
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("HEAD", "repos/OWNER/REPO/releases/tags/v1.2.3"), httpmock.StatusStringResponse(404, ``))
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.RESTPayload(201, `{
@ -776,9 +766,7 @@ func Test_createRun(t *testing.T) {
},
Concurrency: 1,
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("HEAD", "repos/OWNER/REPO/releases/tags/v1.2.3"), httpmock.StatusStringResponse(404, ``))
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.RESTPayload(201, `{
@ -838,9 +826,7 @@ func Test_createRun(t *testing.T) {
},
Concurrency: 1,
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("HEAD", "repos/OWNER/REPO/releases/tags/v1.2.3"), httpmock.StatusStringResponse(200, ``))
},
@ -868,9 +854,7 @@ func Test_createRun(t *testing.T) {
},
Concurrency: 1,
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("HEAD", "repos/OWNER/REPO/releases/tags/v1.2.3"), httpmock.StatusStringResponse(404, ``))
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.StatusStringResponse(201, `{
@ -905,9 +889,7 @@ func Test_createRun(t *testing.T) {
},
Concurrency: 1,
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("HEAD", "repos/OWNER/REPO/releases/tags/v1.2.3"), httpmock.StatusStringResponse(404, ``))
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.StatusStringResponse(201, `{
@ -943,9 +925,7 @@ func Test_createRun(t *testing.T) {
},
Concurrency: 1,
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("HEAD", "repos/OWNER/REPO/releases/tags/v1.2.3"), httpmock.StatusStringResponse(200, ``))
},
@ -974,9 +954,7 @@ func Test_createRun(t *testing.T) {
DiscussionCategory: "general",
Concurrency: 1,
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
runStubs: defaultRunStubs,
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(httpmock.REST("HEAD", "repos/OWNER/REPO/releases/tags/v1.2.3"), httpmock.StatusStringResponse(404, ``))
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.RESTPayload(201, `{
@ -1027,7 +1005,8 @@ func Test_createRun(t *testing.T) {
NotesFromTag: true,
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "some tag message")
rs.Register(contentCmd, 0, "some tag message")
rs.Register(signatureCmd, 0, "")
},
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(
@ -1064,7 +1043,8 @@ func Test_createRun(t *testing.T) {
NotesFromTag: true,
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "some tag message")
rs.Register(contentCmd, 0, "some tag message")
rs.Register(signatureCmd, 0, "")
},
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
reg.Register(
@ -1099,10 +1079,8 @@ func Test_createRun(t *testing.T) {
Assets: []*shared.AssetForUpload(nil),
NotesFromTag: true,
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "")
},
wantErr: "cannot generate release notes from tag v1.2.3 as it does not exist locally",
runStubs: defaultRunStubs,
wantErr: "cannot generate release notes from tag v1.2.3 as it does not exist locally",
},
}
for _, tt := range tests {
@ -1149,6 +1127,13 @@ func Test_createRun(t *testing.T) {
}
func Test_createRun_interactive(t *testing.T) {
const contentCmd = `git tag --list .* --format=%\(contents\)`
const signatureCmd = `git tag --list .* --format=%\(contents:signature\)`
defaultRunStubs := func(rs *run.CommandStubber) {
rs.Register(contentCmd, 1, "")
}
tests := []struct {
name string
httpStubs func(*httpmock.Registry)
@ -1185,9 +1170,7 @@ func Test_createRun_interactive(t *testing.T) {
return false, nil
})
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 1, "")
},
runStubs: defaultRunStubs,
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.REST("GET", "repos/OWNER/REPO/tags"), httpmock.StatusStringResponse(200, `[
{ "name": "v1.2.3" }, { "name": "v1.2.2" }, { "name": "v1.0.0" }, { "name": "v0.1.2" }
@ -1234,9 +1217,7 @@ func Test_createRun_interactive(t *testing.T) {
return false, nil
})
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 1, "")
},
runStubs: defaultRunStubs,
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.REST("GET", "repos/OWNER/REPO/tags"), httpmock.StatusStringResponse(200, `[
{ "name": "v1.2.2" }, { "name": "v1.0.0" }, { "name": "v0.1.2" }
@ -1283,9 +1264,7 @@ func Test_createRun_interactive(t *testing.T) {
return false, nil
})
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 1, "")
},
runStubs: defaultRunStubs,
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.REST("GET", "repos/OWNER/REPO/tags"), httpmock.StatusStringResponse(200, `[
{ "name": "v1.2.2" }, { "name": "v1.0.0" }, { "name": "v0.1.2" }
@ -1332,9 +1311,7 @@ func Test_createRun_interactive(t *testing.T) {
return false, nil
})
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 1, "")
},
runStubs: defaultRunStubs,
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases/generate-notes"),
httpmock.StatusStringResponse(200, `{
@ -1381,7 +1358,7 @@ func Test_createRun_interactive(t *testing.T) {
})
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 1, "")
defaultRunStubs(rs)
rs.Register(`git describe --tags --abbrev=0 HEAD\^`, 0, "v1.2.2\n")
rs.Register(`git .+log .+v1\.2\.2\.\.HEAD$`, 0, "commit subject\n\ncommit body\n")
},
@ -1427,7 +1404,8 @@ func Test_createRun_interactive(t *testing.T) {
})
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "hello from annotated tag")
rs.Register(contentCmd, 0, "hello from annotated tag")
rs.Register(signatureCmd, 0, "")
rs.Register(`git describe --tags --abbrev=0 v1\.2\.3\^`, 1, "")
},
httpStubs: func(reg *httpmock.Registry) {
@ -1456,7 +1434,8 @@ func Test_createRun_interactive(t *testing.T) {
TagName: "v1.2.3",
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "tag exists")
rs.Register(contentCmd, 0, "tag exists")
rs.Register(signatureCmd, 0, "")
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.GraphQL("RepositoryFindRef"),
@ -1489,7 +1468,8 @@ func Test_createRun_interactive(t *testing.T) {
})
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "tag exists")
rs.Register(contentCmd, 0, "tag exists")
rs.Register(signatureCmd, 0, "")
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases/generate-notes"),
@ -1536,9 +1516,7 @@ func Test_createRun_interactive(t *testing.T) {
return false, nil
})
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 1, "")
},
runStubs: defaultRunStubs,
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases/generate-notes"),
httpmock.RESTPayload(200, `{
@ -1591,7 +1569,7 @@ func Test_createRun_interactive(t *testing.T) {
})
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 1, "")
defaultRunStubs(rs)
rs.Register(`git .+log .+v1\.1\.0\.\.HEAD$`, 0, "commit subject\n\ncommit body\n")
},
httpStubs: func(reg *httpmock.Registry) {
@ -1639,7 +1617,8 @@ func Test_createRun_interactive(t *testing.T) {
})
},
runStubs: func(rs *run.CommandStubber) {
rs.Register(`git tag --list`, 0, "tag exists")
rs.Register(contentCmd, 0, "tag exists")
rs.Register(signatureCmd, 0, "")
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.GraphQL("RepositoryFindRef"),
@ -1751,6 +1730,106 @@ func Test_createRun_interactive(t *testing.T) {
}
}
func Test_gitTagInfo(t *testing.T) {
const tagName = "foo"
const contentCmd = `git tag --list foo --format=%\(contents\)`
const signatureCmd = `git tag --list foo --format=%\(contents:signature\)`
tests := []struct {
name string
runStubs func(*run.CommandStubber)
wantErr string
wantResult string
}{
{
name: "no signature",
runStubs: func(cs *run.CommandStubber) {
cs.Register(contentCmd, 0, "some\nmultiline\ncontent")
cs.Register(signatureCmd, 0, "")
},
wantResult: "some\nmultiline\ncontent",
},
{
name: "with signature (PGP)",
runStubs: func(cs *run.CommandStubber) {
cs.Register(contentCmd, 0, "some\nmultiline\ncontent\n-----BEGIN PGP SIGNATURE-----\n\nfoo\n-----END PGP SIGNATURE-----")
cs.Register(signatureCmd, 0, "-----BEGIN PGP SIGNATURE-----\n\nfoo\n-----END PGP SIGNATURE-----")
},
wantResult: "some\nmultiline\ncontent",
},
{
name: "with signature (PGP, RFC1991)",
runStubs: func(cs *run.CommandStubber) {
cs.Register(contentCmd, 0, "some\nmultiline\ncontent\n-----BEGIN PGP MESSAGE-----\n\nfoo\n-----END PGP MESSAGE-----")
cs.Register(signatureCmd, 0, "-----BEGIN PGP MESSAGE-----\n\nfoo\n-----END PGP MESSAGE-----")
},
wantResult: "some\nmultiline\ncontent",
},
{
name: "with signature (SSH)",
runStubs: func(cs *run.CommandStubber) {
cs.Register(contentCmd, 0, "some\nmultiline\ncontent\n-----BEGIN SSH SIGNATURE-----\nfoo\n-----END SSH SIGNATURE-----")
cs.Register(signatureCmd, 0, "-----BEGIN SSH SIGNATURE-----\nfoo\n-----END SSH SIGNATURE-----")
},
wantResult: "some\nmultiline\ncontent",
},
{
name: "with signature (X.509)",
runStubs: func(cs *run.CommandStubber) {
cs.Register(contentCmd, 0, "some\nmultiline\ncontent\n-----BEGIN SIGNED MESSAGE-----\nfoo\n-----END SIGNED MESSAGE-----")
cs.Register(signatureCmd, 0, "-----BEGIN SIGNED MESSAGE-----\nfoo\n-----END SIGNED MESSAGE-----")
},
wantResult: "some\nmultiline\ncontent",
},
{
name: "with signature in content but not as true signature",
runStubs: func(cs *run.CommandStubber) {
cs.Register(contentCmd, 0, "some\nmultiline\ncontent\n-----BEGIN PGP SIGNATURE-----\n\nfoo\n-----END PGP SIGNATURE-----")
cs.Register(signatureCmd, 0, "")
},
wantResult: "some\nmultiline\ncontent\n-----BEGIN PGP SIGNATURE-----\n\nfoo\n-----END PGP SIGNATURE-----",
},
{
name: "error getting content",
runStubs: func(cs *run.CommandStubber) {
cs.Register(contentCmd, 1, "some error")
},
wantErr: fmt.Sprintf("failed to run git: %s exited with status 1", contentCmd),
},
{
name: "error getting signature",
runStubs: func(cs *run.CommandStubber) {
cs.Register(contentCmd, 0, "whatever")
cs.Register(signatureCmd, 1, "some error")
},
wantErr: fmt.Sprintf("failed to run git: %s exited with status 1", signatureCmd),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gitClient := &git.Client{GitPath: "some/path/git"}
rs, teardown := run.Stub()
defer teardown(t)
if tt.runStubs != nil {
tt.runStubs(rs)
}
result, err := gitTagInfo(gitClient, tagName)
if tt.wantErr != "" {
require.EqualError(t, err, tt.wantErr)
return
} else {
require.NoError(t, err)
}
assert.Equal(t, tt.wantResult, result)
})
}
}
func boolPtr(b bool) *bool {
return &b
}

View file

@ -88,7 +88,7 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
To create a remote repository non-interactively, supply the repository name and one of %[1]s--public%[1]s, %[1]s--private%[1]s, or %[1]s--internal%[1]s.
Pass %[1]s--clone%[1]s to clone the new repository locally.
If the %[1]sOWNER/%[1]s portion of the %[1]sOWNER/REPO%[1]s name argument is omitted, it
If the %[1]sOWNER/%[1]s portion of the %[1]sOWNER/REPO%[1]s name argument is omitted, it
defaults to the name of the authenticating user.
To create a remote repository from an existing local repository, specify the source directory with %[1]s--source%[1]s.

View file

@ -79,18 +79,18 @@ func NewCmdRepoCredits(f *cmdutil.Factory, runF func(*CreditsOptions) error) *co
Use: "credits [<repository>]",
Short: "View credits for a repository",
Example: heredoc.Doc(`
# view credits for the current repository
$ gh repo credits
# view credits for the current repository
$ gh repo credits
# view credits for a specific repository
$ gh repo credits cool/repo
# view credits for a specific repository
$ gh repo credits cool/repo
# print a non-animated thank you
$ gh repo credits -s
# print a non-animated thank you
$ gh repo credits -s
# pipe to just print the contributors, one per line
$ gh repo credits | cat
`),
# pipe to just print the contributors, one per line
$ gh repo credits | cat
`),
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {

View file

@ -121,12 +121,11 @@ func setDefaultRun(opts *SetDefaultOptions) error {
if opts.ViewMode {
if currentDefaultRepo != nil {
fmt.Fprintln(opts.IO.Out, displayRemoteRepoName(currentDefaultRepo))
} else if opts.IO.IsStdoutTTY() {
fmt.Fprintln(opts.IO.Out, "no default repository has been set; use `gh repo set-default` to select one")
} else {
fmt.Fprintln(opts.IO.ErrOut, "no default repository has been set; use `gh repo set-default` to select one")
}
return nil
}
cs := opts.IO.ColorScheme()
if opts.UnsetMode {

View file

@ -135,6 +135,7 @@ func TestDefaultRun(t *testing.T) {
gitStubs func(*run.CommandStubber)
prompterStubs func(*prompter.PrompterMock)
wantStdout string
wantStderr string
wantErr bool
errMsg string
}{
@ -175,10 +176,11 @@ func TestDefaultRun(t *testing.T) {
Repo: repo1,
},
},
wantStdout: "no default repository has been set; use `gh repo set-default` to select one\n",
wantStderr: "no default repository has been set; use `gh repo set-default` to select one\n",
},
{
name: "view mode no current default",
tty: false,
opts: SetDefaultOptions{ViewMode: true},
remotes: []*context.Remote{
{
@ -186,6 +188,7 @@ func TestDefaultRun(t *testing.T) {
Repo: repo1,
},
},
wantStderr: "no default repository has been set; use `gh repo set-default` to select one\n",
},
{
name: "view mode with base resolved current default",
@ -466,7 +469,7 @@ func TestDefaultRun(t *testing.T) {
return &http.Client{Transport: reg}, nil
}
io, _, stdout, _ := iostreams.Test()
io, _, stdout, stderr := iostreams.Test()
io.SetStdinTTY(tt.tty)
io.SetStdoutTTY(tt.tty)
io.SetStderrTTY(tt.tty)
@ -498,7 +501,11 @@ func TestDefaultRun(t *testing.T) {
return
}
assert.NoError(t, err)
assert.Equal(t, tt.wantStdout, stdout.String())
if tt.wantStdout != "" {
assert.Equal(t, tt.wantStdout, stdout.String())
} else {
assert.Equal(t, tt.wantStderr, stderr.String())
}
})
}
}

View file

@ -45,13 +45,15 @@ func NewCmdView(f *cmdutil.Factory, runF func(*ViewOptions) error) *cobra.Comman
cmd := &cobra.Command{
Use: "view [<repository>]",
Short: "View a repository",
Long: `Display the description and the README of a GitHub repository.
Long: heredoc.Docf(`
Display the description and the README of a GitHub repository.
With no argument, the repository for the current directory is displayed.
With no argument, the repository for the current directory is displayed.
With '--web', open the repository in a web browser instead.
With %[1]s--web%[1]s, open the repository in a web browser instead.
With '--branch', view a specific branch of the repository.`,
With %[1]s--branch%[1]s, view a specific branch of the repository.
`, "`"),
Args: cobra.MaximumNArgs(1),
RunE: func(c *cobra.Command, args []string) error {
if len(args) > 0 {

View file

@ -182,6 +182,7 @@ func rootHelpFunc(f *cmdutil.Factory, command *cobra.Command, args []string) {
helpEntries = append(helpEntries, helpEntry{"LEARN MORE", heredoc.Docf(`
Use %[1]sgh <command> <subcommand> --help%[1]s for more information about a command.
Read the manual at https://cli.github.com/manual
Learn about exit codes using %[1]sgh help exit-codes%[1]s
`, "`")})
out := f.IOStreams.Out

View file

@ -158,25 +158,25 @@ var HelpTopics = []helpTopic{
$ gh pr list --json number,title,author
[
{
"author": {
"login": "monalisa"
},
"number": 123,
"title": "A helpful contribution"
"author": {
"login": "monalisa"
},
"number": 123,
"title": "A helpful contribution"
},
{
"author": {
"login": "codercat"
},
"number": 124,
"title": "Improve the docs"
"author": {
"login": "codercat"
},
"number": 124,
"title": "Improve the docs"
},
{
"author": {
"login": "cli-maintainer"
},
"number": 125,
"title": "An exciting new feature"
"author": {
"login": "cli-maintainer"
},
"number": 125,
"title": "An exciting new feature"
}
]
@ -193,32 +193,31 @@ var HelpTopics = []helpTopic{
| map(.labels = (.labels | map(.name))) # show only the label names
| .[:3] # select the first 3 results'
[
{
"labels": [
"enhancement",
"needs triage"
],
"number": 123,
"title": "A helpful contribution"
},
{
"labels": [
"help wanted",
"docs",
"good first issue"
],
"number": 125,
"title": "Improve the docs"
},
{
"labels": [
"enhancement",
],
"number": 7221,
"title": "An exciting new feature"
}
{
"labels": [
"enhancement",
"needs triage"
],
"number": 123,
"title": "A helpful contribution"
},
{
"labels": [
"help wanted",
"docs",
"good first issue"
],
"number": 125,
"title": "Improve the docs"
},
{
"labels": [
"enhancement",
],
"number": 7221,
"title": "An exciting new feature"
}
]
# using the --template flag with the hyperlink helper
gh issue list --json title,url --template '{{range .}}{{hyperlink .url .title}}{{"\n"}}{{end}}'

View file

@ -42,26 +42,30 @@ func NewCmdDownload(f *cmdutil.Factory, runF func(*DownloadOptions) error) *cobr
cmd := &cobra.Command{
Use: "download [<run-id>]",
Short: "Download artifacts generated by a workflow run",
Long: heredoc.Doc(`
Long: heredoc.Docf(`
Download artifacts generated by a GitHub Actions workflow run.
The contents of each artifact will be extracted under separate directories based on
the artifact name. If only a single artifact is specified, it will be extracted into
the current directory.
`),
By default, this command downloads the latest artifact created and uploaded through
GitHub Actions. Because workflows can delete or overwrite artifacts, %[1]s<run-id>%[1]s
must be used to select an artifact from a specific workflow run.
`, "`"),
Args: cobra.MaximumNArgs(1),
Example: heredoc.Doc(`
# Download all artifacts generated by a workflow run
$ gh run download <run-id>
# Download all artifacts generated by a workflow run
$ gh run download <run-id>
# Download a specific artifact within a run
$ gh run download <run-id> -n <name>
# Download a specific artifact within a run
$ gh run download <run-id> -n <name>
# Download specific artifacts across all runs in a repository
$ gh run download -n <name1> -n <name2>
# Download specific artifacts across all runs in a repository
$ gh run download -n <name1> -n <name2>
# Select artifacts to download interactively
$ gh run download
# Select artifacts to download interactively
$ gh run download
`),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {

View file

@ -58,7 +58,7 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
Use: "list",
Short: "List recent workflow runs",
Long: heredoc.Docf(`
List recent workflow runs.
List recent workflow runs.
Note that providing the %[1]sworkflow_name%[1]s to the %[1]s-w%[1]s flag will not fetch disabled workflows.
Also pass the %[1]s-a%[1]s flag to fetch disabled workflow runs using the %[1]sworkflow_name%[1]s and the %[1]s-w%[1]s flag.

View file

@ -45,7 +45,7 @@ func NewCmdCommits(f *cmdutil.Factory, runF func(*CommitsOptions) error) *cobra.
GitHub search syntax is documented at:
<https://docs.github.com/search-github/searching-on-github/searching-commits>
`),
`),
Example: heredoc.Doc(`
# search commits matching set of keywords "readme" and "typo"
$ gh search commits readme typo
@ -64,7 +64,7 @@ func NewCmdCommits(f *cmdutil.Factory, runF func(*CommitsOptions) error) *cobra.
# search commits authored before February 1st, 2022
$ gh search commits --author-date="<2022-02-01"
`),
`),
RunE: func(c *cobra.Command, args []string) error {
if len(args) == 0 && c.Flags().NFlag() == 0 {
return cmdutil.FlagErrorf("specify search keywords or flags")

View file

@ -34,7 +34,7 @@ func NewCmdIssues(f *cmdutil.Factory, runF func(*shared.IssuesOptions) error) *c
GitHub search syntax is documented at:
<https://docs.github.com/search-github/searching-on-github/searching-issues-and-pull-requests>
`),
`),
Example: heredoc.Doc(`
# search issues matching set of keywords "readme" and "typo"
$ gh search issues readme typo
@ -56,8 +56,7 @@ func NewCmdIssues(f *cmdutil.Factory, runF func(*shared.IssuesOptions) error) *c
# search issues only from un-archived repositories (default is all repositories)
$ gh search issues --owner github --archived=false
`),
`),
RunE: func(c *cobra.Command, args []string) error {
if len(args) == 0 && c.Flags().NFlag() == 0 {
return cmdutil.FlagErrorf("specify search keywords or flags")

View file

@ -36,7 +36,7 @@ func NewCmdPrs(f *cmdutil.Factory, runF func(*shared.IssuesOptions) error) *cobr
GitHub search syntax is documented at:
<https://docs.github.com/search-github/searching-on-github/searching-issues-and-pull-requests>
`),
`),
Example: heredoc.Doc(`
# search pull requests matching set of keywords "fix" and "bug"
$ gh search prs fix bug
@ -58,7 +58,7 @@ func NewCmdPrs(f *cmdutil.Factory, runF func(*shared.IssuesOptions) error) *cobr
# search pull requests only from un-archived repositories (default is all repositories)
$ gh search prs --owner github --archived=false
`),
`),
RunE: func(c *cobra.Command, args []string) error {
if len(args) == 0 && c.Flags().NFlag() == 0 {
return cmdutil.FlagErrorf("specify search keywords or flags")

View file

@ -46,7 +46,7 @@ func NewCmdRepos(f *cmdutil.Factory, runF func(*ReposOptions) error) *cobra.Comm
GitHub search syntax is documented at:
<https://docs.github.com/search-github/searching-on-github/searching-for-repositories>
`),
`),
Example: heredoc.Doc(`
# search repositories matching set of keywords "cli" and "shell"
$ gh search repos cli shell
@ -68,7 +68,7 @@ func NewCmdRepos(f *cmdutil.Factory, runF func(*ReposOptions) error) *cobra.Comm
# search repositories excluding archived repositories
$ gh search repos --archived=false
`),
`),
RunE: func(c *cobra.Command, args []string) error {
if len(args) == 0 && c.Flags().NFlag() == 0 {
return cmdutil.FlagErrorf("specify search keywords or flags")

View file

@ -105,24 +105,27 @@ func removeRun(opts *DeleteOptions) error {
}
}
var path string
switch secretEntity {
case shared.Organization:
path = fmt.Sprintf("orgs/%s/%s/secrets/%s", orgName, secretApp, opts.SecretName)
case shared.Environment:
path = fmt.Sprintf("repos/%s/environments/%s/secrets/%s", ghrepo.FullName(baseRepo), envName, opts.SecretName)
case shared.User:
path = fmt.Sprintf("user/codespaces/secrets/%s", opts.SecretName)
case shared.Repository:
path = fmt.Sprintf("repos/%s/%s/secrets/%s", ghrepo.FullName(baseRepo), secretApp, opts.SecretName)
}
cfg, err := opts.Config()
if err != nil {
return err
}
host, _ := cfg.Authentication().DefaultHost()
var path string
var host string
switch secretEntity {
case shared.Organization:
path = fmt.Sprintf("orgs/%s/%s/secrets/%s", orgName, secretApp, opts.SecretName)
host, _ = cfg.Authentication().DefaultHost()
case shared.Environment:
path = fmt.Sprintf("repos/%s/environments/%s/secrets/%s", ghrepo.FullName(baseRepo), envName, opts.SecretName)
host = baseRepo.RepoHost()
case shared.User:
path = fmt.Sprintf("user/codespaces/secrets/%s", opts.SecretName)
host, _ = cfg.Authentication().DefaultHost()
case shared.Repository:
path = fmt.Sprintf("repos/%s/%s/secrets/%s", ghrepo.FullName(baseRepo), secretApp, opts.SecretName)
host = baseRepo.RepoHost()
}
err = client.REST(host, "DELETE", path, nil, nil)
if err != nil {

View file

@ -13,6 +13,7 @@ import (
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/google/shlex"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewCmdDelete(t *testing.T) {
@ -121,9 +122,10 @@ func TestNewCmdDelete(t *testing.T) {
func Test_removeRun_repo(t *testing.T) {
tests := []struct {
name string
opts *DeleteOptions
wantPath string
name string
opts *DeleteOptions
host string
httpStubs func(*httpmock.Registry)
}{
{
name: "Actions",
@ -131,7 +133,21 @@ func Test_removeRun_repo(t *testing.T) {
Application: "actions",
SecretName: "cool_secret",
},
wantPath: "repos/owner/repo/actions/secrets/cool_secret",
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "repos/owner/repo/actions/secrets/cool_secret"), "api.github.com"), httpmock.StatusStringResponse(204, "No Content"))
},
},
{
name: "Actions GHES",
opts: &DeleteOptions{
Application: "actions",
SecretName: "cool_secret",
},
host: "example.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "api/v3/repos/owner/repo/actions/secrets/cool_secret"), "example.com"), httpmock.StatusStringResponse(204, "No Content"))
},
},
{
name: "Dependabot",
@ -139,23 +155,38 @@ func Test_removeRun_repo(t *testing.T) {
Application: "dependabot",
SecretName: "cool_dependabot_secret",
},
wantPath: "repos/owner/repo/dependabot/secrets/cool_dependabot_secret",
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "repos/owner/repo/dependabot/secrets/cool_dependabot_secret"), "api.github.com"), httpmock.StatusStringResponse(204, "No Content"))
},
},
{
name: "Dependabot GHES",
opts: &DeleteOptions{
Application: "dependabot",
SecretName: "cool_dependabot_secret",
},
host: "example.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "api/v3/repos/owner/repo/dependabot/secrets/cool_dependabot_secret"), "example.com"), httpmock.StatusStringResponse(204, "No Content"))
},
},
{
name: "defaults to Actions",
opts: &DeleteOptions{
SecretName: "cool_secret",
},
wantPath: "repos/owner/repo/actions/secrets/cool_secret",
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "repos/owner/repo/actions/secrets/cool_secret"), "api.github.com"), httpmock.StatusStringResponse(204, "No Content"))
},
},
}
for _, tt := range tests {
reg := &httpmock.Registry{}
reg.Register(
httpmock.REST("DELETE", tt.wantPath),
httpmock.StatusStringResponse(204, "No Content"))
tt.httpStubs(reg)
defer reg.Verify(t)
ios, _, _, _ := iostreams.Test()
@ -167,44 +198,70 @@ func Test_removeRun_repo(t *testing.T) {
return config.NewBlankConfig(), nil
}
tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
return ghrepo.FromFullName("owner/repo")
return ghrepo.FromFullNameWithHost("owner/repo", tt.host)
}
err := removeRun(tt.opts)
assert.NoError(t, err)
reg.Verify(t)
}
}
func Test_removeRun_env(t *testing.T) {
reg := &httpmock.Registry{}
reg.Register(
httpmock.REST("DELETE", "repos/owner/repo/environments/development/secrets/cool_secret"),
httpmock.StatusStringResponse(204, "No Content"))
ios, _, _, _ := iostreams.Test()
opts := &DeleteOptions{
IO: ios,
HttpClient: func() (*http.Client, error) {
return &http.Client{Transport: reg}, nil
tests := []struct {
name string
opts *DeleteOptions
host string
httpStubs func(*httpmock.Registry)
}{
{
name: "delete environment secret",
opts: &DeleteOptions{
SecretName: "cool_secret",
EnvName: "development",
},
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "repos/owner/repo/environments/development/secrets/cool_secret"), "api.github.com"),
httpmock.StatusStringResponse(204, "No Content"))
},
},
Config: func() (gh.Config, error) {
return config.NewBlankConfig(), nil
{
name: "delete environment secret GHES",
opts: &DeleteOptions{
SecretName: "cool_secret",
EnvName: "development",
},
host: "example.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "api/v3/repos/owner/repo/environments/development/secrets/cool_secret"), "example.com"),
httpmock.StatusStringResponse(204, "No Content"))
},
},
BaseRepo: func() (ghrepo.Interface, error) {
return ghrepo.FromFullName("owner/repo")
},
SecretName: "cool_secret",
EnvName: "development",
}
err := removeRun(opts)
assert.NoError(t, err)
for _, tt := range tests {
reg := &httpmock.Registry{}
tt.httpStubs(reg)
defer reg.Verify(t)
reg.Verify(t)
ios, _, _, _ := iostreams.Test()
tt.opts.IO = ios
tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
if tt.host != "" {
return ghrepo.FromFullNameWithHost("owner/repo", tt.host)
}
return ghrepo.FromFullName("owner/repo")
}
tt.opts.HttpClient = func() (*http.Client, error) {
return &http.Client{Transport: reg}, nil
}
tt.opts.Config = func() (gh.Config, error) {
return config.NewBlankConfig(), nil
}
err := removeRun(tt.opts)
require.NoError(t, err)
}
}
func Test_removeRun_org(t *testing.T) {

View file

@ -91,22 +91,24 @@ func removeRun(opts *DeleteOptions) error {
}
}
var path string
switch variableEntity {
case shared.Organization:
path = fmt.Sprintf("orgs/%s/actions/variables/%s", orgName, opts.VariableName)
case shared.Environment:
path = fmt.Sprintf("repos/%s/environments/%s/variables/%s", ghrepo.FullName(baseRepo), envName, opts.VariableName)
case shared.Repository:
path = fmt.Sprintf("repos/%s/actions/variables/%s", ghrepo.FullName(baseRepo), opts.VariableName)
}
cfg, err := opts.Config()
if err != nil {
return err
}
host, _ := cfg.Authentication().DefaultHost()
var path string
var host string
switch variableEntity {
case shared.Organization:
path = fmt.Sprintf("orgs/%s/actions/variables/%s", orgName, opts.VariableName)
host, _ = cfg.Authentication().DefaultHost()
case shared.Environment:
path = fmt.Sprintf("repos/%s/environments/%s/variables/%s", ghrepo.FullName(baseRepo), envName, opts.VariableName)
host = baseRepo.RepoHost()
case shared.Repository:
path = fmt.Sprintf("repos/%s/actions/variables/%s", ghrepo.FullName(baseRepo), opts.VariableName)
host = baseRepo.RepoHost()
}
err = client.REST(host, "DELETE", path, nil, nil)
if err != nil {

View file

@ -13,6 +13,7 @@ import (
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/google/shlex"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewCmdDelete(t *testing.T) {
@ -87,16 +88,32 @@ func TestNewCmdDelete(t *testing.T) {
func TestRemoveRun(t *testing.T) {
tests := []struct {
name string
opts *DeleteOptions
wantPath string
name string
opts *DeleteOptions
host string
httpStubs func(*httpmock.Registry)
}{
{
name: "repo",
opts: &DeleteOptions{
VariableName: "cool_variable",
},
wantPath: "repos/owner/repo/actions/variables/cool_variable",
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "repos/owner/repo/actions/variables/cool_variable"), "api.github.com"),
httpmock.StatusStringResponse(204, "No Content"))
},
},
{
name: "repo GHES",
opts: &DeleteOptions{
VariableName: "cool_variable",
},
host: "example.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "api/v3/repos/owner/repo/actions/variables/cool_variable"), "example.com"),
httpmock.StatusStringResponse(204, "No Content"))
},
},
{
name: "env",
@ -104,7 +121,23 @@ func TestRemoveRun(t *testing.T) {
VariableName: "cool_variable",
EnvName: "development",
},
wantPath: "repos/owner/repo/environments/development/variables/cool_variable",
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "repos/owner/repo/environments/development/variables/cool_variable"), "api.github.com"),
httpmock.StatusStringResponse(204, "No Content"))
},
},
{
name: "env GHES",
opts: &DeleteOptions{
VariableName: "cool_variable",
EnvName: "development",
},
host: "example.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "api/v3/repos/owner/repo/environments/development/variables/cool_variable"), "example.com"),
httpmock.StatusStringResponse(204, "No Content"))
},
},
{
name: "org",
@ -112,35 +145,34 @@ func TestRemoveRun(t *testing.T) {
VariableName: "cool_variable",
OrgName: "UmbrellaCorporation",
},
wantPath: "orgs/UmbrellaCorporation/actions/variables/cool_variable",
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("DELETE", "orgs/UmbrellaCorporation/actions/variables/cool_variable"), "api.github.com"),
httpmock.StatusStringResponse(204, "No Content"))
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
reg := &httpmock.Registry{}
tt.httpStubs(reg)
defer reg.Verify(t)
reg.Register(httpmock.REST("DELETE", tt.wantPath),
httpmock.StatusStringResponse(204, "No Content"))
ios, _, _, _ := iostreams.Test()
tt.opts.IO = ios
tt.opts.HttpClient = func() (*http.Client, error) {
return &http.Client{Transport: reg}, nil
}
tt.opts.Config = func() (gh.Config, error) {
return config.NewBlankConfig(), nil
}
tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
return ghrepo.FromFullName("owner/repo")
return ghrepo.FromFullNameWithHost("owner/repo", tt.host)
}
err := removeRun(tt.opts)
assert.NoError(t, err)
require.NoError(t, err)
})
}
}

View file

@ -92,22 +92,24 @@ func getRun(opts *GetOptions) error {
}
}
var path string
switch variableEntity {
case shared.Organization:
path = fmt.Sprintf("orgs/%s/actions/variables/%s", orgName, opts.VariableName)
case shared.Environment:
path = fmt.Sprintf("repos/%s/environments/%s/variables/%s", ghrepo.FullName(baseRepo), envName, opts.VariableName)
case shared.Repository:
path = fmt.Sprintf("repos/%s/actions/variables/%s", ghrepo.FullName(baseRepo), opts.VariableName)
}
cfg, err := opts.Config()
if err != nil {
return err
}
host, _ := cfg.Authentication().DefaultHost()
var path string
var host string
switch variableEntity {
case shared.Organization:
path = fmt.Sprintf("orgs/%s/actions/variables/%s", orgName, opts.VariableName)
host, _ = cfg.Authentication().DefaultHost()
case shared.Environment:
path = fmt.Sprintf("repos/%s/environments/%s/variables/%s", ghrepo.FullName(baseRepo), envName, opts.VariableName)
host = baseRepo.RepoHost()
case shared.Repository:
path = fmt.Sprintf("repos/%s/actions/variables/%s", ghrepo.FullName(baseRepo), opts.VariableName)
host = baseRepo.RepoHost()
}
var variable shared.Variable
if err = client.REST(host, "GET", path, nil, &variable); err != nil {

View file

@ -110,6 +110,7 @@ func Test_getRun(t *testing.T) {
tests := []struct {
name string
opts *GetOptions
host string
httpStubs func(*httpmock.Registry)
jsonFields []string
wantOut string
@ -120,8 +121,23 @@ func Test_getRun(t *testing.T) {
opts: &GetOptions{
VariableName: "VARIABLE_ONE",
},
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.REST("GET", "repos/owner/repo/actions/variables/VARIABLE_ONE"),
reg.Register(httpmock.WithHost(httpmock.REST("GET", "repos/owner/repo/actions/variables/VARIABLE_ONE"), "api.github.com"),
httpmock.JSONResponse(shared.Variable{
Value: "repo_var",
}))
},
wantOut: "repo_var\n",
},
{
name: "getting GHES repo variable",
opts: &GetOptions{
VariableName: "VARIABLE_ONE",
},
host: "example.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("GET", "api/v3/repos/owner/repo/actions/variables/VARIABLE_ONE"), "example.com"),
httpmock.JSONResponse(shared.Variable{
Value: "repo_var",
}))
@ -134,6 +150,7 @@ func Test_getRun(t *testing.T) {
OrgName: "TestOrg",
VariableName: "VARIABLE_ONE",
},
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.REST("GET", "orgs/TestOrg/actions/variables/VARIABLE_ONE"),
httpmock.JSONResponse(shared.Variable{
@ -148,8 +165,24 @@ func Test_getRun(t *testing.T) {
EnvName: "Development",
VariableName: "VARIABLE_ONE",
},
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.REST("GET", "repos/owner/repo/environments/Development/variables/VARIABLE_ONE"),
reg.Register(httpmock.WithHost(httpmock.REST("GET", "repos/owner/repo/environments/Development/variables/VARIABLE_ONE"), "api.github.com"),
httpmock.JSONResponse(shared.Variable{
Value: "env_var",
}))
},
wantOut: "env_var\n",
},
{
name: "getting GHES env variable",
opts: &GetOptions{
EnvName: "Development",
VariableName: "VARIABLE_ONE",
},
host: "example.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.WithHost(httpmock.REST("GET", "api/v3/repos/owner/repo/environments/Development/variables/VARIABLE_ONE"), "example.com"),
httpmock.JSONResponse(shared.Variable{
Value: "env_var",
}))
@ -161,6 +194,7 @@ func Test_getRun(t *testing.T) {
opts: &GetOptions{
VariableName: "VARIABLE_ONE",
},
host: "github.com",
jsonFields: []string{"name", "value", "visibility", "updatedAt", "createdAt", "numSelectedRepos", "selectedReposURL"},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.REST("GET", "repos/owner/repo/actions/variables/VARIABLE_ONE"),
@ -193,6 +227,7 @@ func Test_getRun(t *testing.T) {
opts: &GetOptions{
VariableName: "VARIABLE_ONE",
},
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.REST("GET", "repos/owner/repo/actions/variables/VARIABLE_ONE"),
httpmock.StatusStringResponse(404, "not found"),
@ -205,6 +240,7 @@ func Test_getRun(t *testing.T) {
opts: &GetOptions{
VariableName: "VARIABLE_ONE",
},
host: "github.com",
httpStubs: func(reg *httpmock.Registry) {
reg.Register(httpmock.REST("GET", "repos/owner/repo/actions/variables/VARIABLE_ONE"),
httpmock.StatusStringResponse(400, "not found"),
@ -226,7 +262,7 @@ func Test_getRun(t *testing.T) {
tt.opts.IO = ios
tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
return ghrepo.FromFullName("owner/repo")
return ghrepo.FromFullNameWithHost("owner/repo", tt.host)
}
tt.opts.HttpClient = func() (*http.Client, error) {
return &http.Client{Transport: reg}, nil

View file

@ -17,7 +17,7 @@ func NewCmdVariable(f *cmdutil.Factory) *cobra.Command {
Long: heredoc.Docf(`
Variables can be set at the repository, environment or organization level for use in
GitHub Actions or Dependabot. Run %[1]sgh help variable set%[1]s to learn how to get started.
`, "`"),
`, "`"),
}
cmdutil.EnableRepoOverride(cmd, f)

View file

@ -64,7 +64,7 @@ func NewCmdRun(f *cmdutil.Factory, runF func(*RunOptions) error) *cobra.Command
- Interactively
- Via %[1]s-f/--raw-field%[1]s or %[1]s-F/--field%[1]s flags
- As JSON, via standard input
`, "`"),
`, "`"),
Example: heredoc.Doc(`
# Have gh prompt you for what workflow you'd like to run and interactively collect inputs
$ gh workflow run

View file

@ -56,11 +56,11 @@ func NewCmdView(f *cmdutil.Factory, runF func(*ViewOptions) error) *cobra.Comman
Short: "View the summary of a workflow",
Args: cobra.MaximumNArgs(1),
Example: heredoc.Doc(`
# Interactively select a workflow to view
$ gh workflow view
# Interactively select a workflow to view
$ gh workflow view
# View a specific workflow
$ gh workflow view 0451
# View a specific workflow
$ gh workflow view 0451
`),
RunE: func(cmd *cobra.Command, args []string) error {
// support `-R, --repo` override

View file

@ -123,6 +123,15 @@ func StringResponse(body string) Responder {
}
}
func WithHost(matcher Matcher, host string) Matcher {
return func(req *http.Request) bool {
if !strings.EqualFold(req.Host, host) {
return false
}
return matcher(req)
}
}
func WithHeader(responder Responder, header string, value string) Responder {
return func(req *http.Request) (*http.Response, error) {
resp, _ := responder(req)

View file

@ -46,10 +46,10 @@ var EditorQuestionTemplate = `
{{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}}
{{- color "default+hb"}}{{ .Message }} {{color "reset"}}
{{- if .ShowAnswer}}
{{- color "cyan"}}{{.Answer}}{{color "reset"}}{{"\n"}}
{{- color "cyan"}}{{.Answer}}{{color "reset"}}{{"\n"}}
{{- else }}
{{- if and .Help (not .ShowHelp)}}{{color "cyan"}}[{{ .Config.HelpInput }} for help]{{color "reset"}} {{end}}
{{- if and .Default (not .HideDefault)}}{{color "white"}}({{.Default}}) {{color "reset"}}{{end}}
{{- if and .Help (not .ShowHelp)}}{{color "cyan"}}[{{ .Config.HelpInput }} for help]{{color "reset"}} {{end}}
{{- if and .Default (not .HideDefault)}}{{color "white"}}({{.Default}}) {{color "reset"}}{{end}}
{{- color "cyan"}}[(e) to launch {{ .EditorCommand }}{{- if .BlankAllowed }}, enter to skip{{ end }}] {{color "reset"}}
{{- end}}`