Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@malancas
Copy link
Contributor

@malancas malancas commented Oct 30, 2024

This is an initial refactor of how gh attestation verify handles policy enforcement. It consolidates the logic used to evaluate policy options into a single struct.

cc #9850

@malancas malancas changed the title Attestation refactor policy gh attestation verify policy enforcement refactor Oct 30, 2024
Signed-off-by: Meredith Lancaster <[email protected]>
Signed-off-by: Meredith Lancaster <[email protected]>
Signed-off-by: Meredith Lancaster <[email protected]>
Copy link
Contributor

@phillmv phillmv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a ton of comments but I am liking where this is heading!

}

type EnforcementCriteria struct {
Extensions Extensions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not literally embed the CertificateSummary? & store the SANRegex separately. That way we get every field by default.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Extensions Extensions
Certificate certificate.Summary

or w/e

Extensions Extensions
PredicateType string
Artifact artifact.DigestedArtifact
OIDCIssuer string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the topic of embedding the CertificateSummary, since we have to compare the Issuer every time, we can move this inside the Certificate

return fmt.Errorf("expected Issuer to be %s, got %s -- if you have a custom OIDC issuer policy for your enterprise, use the --cert-oidc-issuer flag with your expected issuer", want, certIssuer)
} else {
return fmt.Errorf("expected Issuer to be %s, got %s", want, certIssuer)
if c.OIDCIssuer != "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we don't check it elsewhere, c.OIDCIssuer being blank is an error condition 🤔 .

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like, if it is == "" then we should throw an error kind of thing. What are you verifying?

// if tenant is provided, select the appropriate default based on the tenant
// otherwise, use the provided OIDCIssuer
if opts.Tenant != "" {
c.OIDCIssuer = fmt.Sprintf(verification.GitHubTenantOIDCIssuer, opts.Tenant)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a clean mapping of the logic. If you have a tenant you may still specify a custom OIDC issuer, contrast with:

	if issuer != GitHubOIDCIssuer {
		want = issuer
	} else {
		if tenant != "" {
			want = fmt.Sprintf(GitHubTenantOIDCIssuer, tenant)
		} else {
			want = GitHubOIDCIssuer
		}
	}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(if no tests are failing because of this then we should add one)


return verify.SubjectAlternativeNameMatcher{}, nil
if opts.DenySelfHostedRunner {
c.Extensions.RunnerEnvironment = GitHubRunner
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's preserve the comment re: the empty string matching for AnyRunner


func buildSANMatcher(opts *Options) (verify.SubjectAlternativeNameMatcher, error) {
func newEnforcementCriteria(opts *Options, a artifact.DigestedArtifact) (verification.EnforcementCriteria, error) {
c := verification.EnforcementCriteria{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Enforcement criteria maps Options to strings we're verifying. What does having artifact in here buy us?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like, the contents of the opts will never modify the DigestedArtifact, right? so why is it EC's responsibility to be a container for it?


func buildVerifyPolicy(opts *Options, a artifact.DigestedArtifact) (verify.PolicyBuilder, error) {
artifactDigestPolicyOption, err := verification.BuildDigestPolicyOption(a)
func SigstorePolicy(c verification.EnforcementCriteria) (verify.PolicyBuilder, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so here I'd say either

NewSigstoreVerifyPolicy or buildSigstoreVerifyPolicy,

and

  • i feel like it should take the artifact as a param, so we can liberate the enforcement criteria from having to care about the artifact

policy, err := buildVerifyPolicy(opts, *artifact)
opts.Logger.VerbosePrintf("Verifying attestations with predicate type: %s\n", opts.PredicateType)

ec, err := newEnforcementCriteria(opts, *artifact)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imho:

  • this should happen before we even load the bundles. The PredicateType in FilterAttestations should be coming from the ec, not from opts
  • like, even before we digest the artifact. nothing in the EC depends on the artifact or a network call, right?
  • and then right after we call newEnforcementCriteria we should call err := Valid() or w/e.

here I am thinking that ec.Validate() is separate from newEC only in so far that it might be easier to check for invalid states separately from setting them the flags.

for example, if the OIDCIssuer/Certificate.Issuer is empty on the Valid() call then that's an error! but it might not be obvious where to stick that check in the new func.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up creating a separate EnforcementCriteria#Valid method for checking that all required fields are set. It felt a little too crowded doing it in the constructor.

malancas and others added 6 commits October 31, 2024 16:07
Signed-off-by: Meredith Lancaster <[email protected]>
Signed-off-by: Meredith Lancaster <[email protected]>
Signed-off-by: Meredith Lancaster <[email protected]>
@malancas malancas marked this pull request as ready for review October 31, 2024 22:28
@malancas malancas requested a review from a team as a code owner October 31, 2024 22:28
@cliAutomation cliAutomation added the external pull request originating outside of the CLI core team label Oct 31, 2024
Signed-off-by: Meredith Lancaster <[email protected]>
Signed-off-by: Meredith Lancaster <[email protected]>
func newEnforcementCriteria(opts *Options) (verification.EnforcementCriteria, error) {
c := verification.EnforcementCriteria{}

// Set SANRegex using either the opts.SignerRepo or opts.SignerWorkflow values
Copy link
Contributor Author

@malancas malancas Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section of setting SAN and/or SANRegex is using logic originally from

func buildSANMatcher(opts *Options) (verify.SubjectAlternativeNameMatcher, error) {
if opts.SignerRepo != "" {
signedRepoRegex := expandToGitHubURL(opts.Tenant, opts.SignerRepo)
return verify.NewSANMatcher("", signedRepoRegex)
} else if opts.SignerWorkflow != "" {
validatedWorkflowRegex, err := validateSignerWorkflow(opts)
if err != nil {
return verify.SubjectAlternativeNameMatcher{}, err
}
return verify.NewSANMatcher("", validatedWorkflowRegex)
} else if opts.SAN != "" || opts.SANRegex != "" {
return verify.NewSANMatcher(opts.SAN, opts.SANRegex)
}
return verify.SubjectAlternativeNameMatcher{}, nil
}

c.Certificate.RunnerEnvironment = ""
}

// If the Repo option is provided, set the SourceRepositoryURI extension
Copy link
Contributor Author

@malancas malancas Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return fmt.Errorf("expected Issuer to be %s, got %s -- if you have a custom OIDC issuer policy for your enterprise, use the --cert-oidc-issuer flag with your expected issuer", want, certIssuer)
} else {
return fmt.Errorf("expected Issuer to be %s, got %s", want, certIssuer)
if criteria.Certificate.Issuer != "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imho skip the empty check here,: criteria.Certificate.Issuer == "" is always going to be an invalid state.

we now validate this, so it's less risky but, i feel like,

a) this should never generate an error so it's safe to always check, and
b) if this does ever generate an error that'll tell us about a bug somewhere else

🤔

Copy link
Contributor Author

@malancas malancas Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I lean towards not checking for the empty string because of (b) since it exposes a bug and feels less risky now that we have a validation function for the struct.

Signed-off-by: Meredith Lancaster <[email protected]>
Signed-off-by: Meredith Lancaster <[email protected]>
Signed-off-by: Meredith Lancaster <[email protected]>
Copy link
Contributor

@phillmv phillmv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me! I think we landed in a nice clean place that centralizes the logic & makes enforcement decisions easier to reason about & expose to the user (in a future PR).

I'm only not approving because I haven't had the time/mental energy rn to read thru the tests 😄.

malancas and others added 3 commits November 1, 2024 09:51
Signed-off-by: Meredith Lancaster <[email protected]>
Signed-off-by: Meredith Lancaster <[email protected]>
Copy link
Contributor

@ejahnGithub ejahnGithub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@malancas malancas merged commit 446a0d5 into cli:trunk Nov 6, 2024
@malancas malancas deleted the attestation-refactor-policy branch November 6, 2024 14:50
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Nov 21, 2024
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [cli/cli](https://github.com/cli/cli) | minor | `v2.59.0` -> `v2.62.0` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>cli/cli (cli/cli)</summary>

### [`v2.62.0`](https://github.com/cli/cli/releases/tag/v2.62.0): GitHub CLI 2.62.0

[Compare Source](cli/cli@v2.61.0...v2.62.0)

#### What's Changed

-   Update monotonic verification logic and testing by [@&#8203;malancas](https://github.com/malancas) in cli/cli#9856
-   Check extension for latest version when executed by [@&#8203;andyfeller](https://github.com/andyfeller) in cli/cli#9866
-   Shorten extension release checking from 3s to 1s by [@&#8203;andyfeller](https://github.com/andyfeller) in cli/cli#9914
-   Mention GitHub CLI team on discussion issues by [@&#8203;andyfeller](https://github.com/andyfeller) in cli/cli#9920

**Full Changelog**: cli/cli@v2.61.0...v2.62.0

#### Security

-   A security vulnerability has been identified in GitHub CLI that could allow remote code execution (RCE) when users connect to a malicious Codespace SSH server and use the `gh codespace ssh` or `gh codespace logs` commands.

    For more information, see GHSA-p2h2-3vg9-4p87

#### GitHub CLI notifies users about latest extension upgrades

Similar to the notification of latest `gh` releases, the `v2.62.0` version of GitHub CLI will notify users about latest extension upgrades when the extension is used:

```shell
$ gh ado2gh
...

A new release of ado2gh is available: 1.7.0 → 1.8.0
To upgrade, run: gh extension upgrade ado2gh --force
https://github.com/github/gh-ado2gh
```

##### Why does this matter?

This removes a common pain point of extension authors as they have had to reverse engineer and implement a similar mechanism within their extensions directly.

With this quality of life improvement, there are 2 big benefits:

1.  Extension authors will hopefully see increased adoption of newer releases while having lower bar to maintaining their extensions.
2.  GitHub CLI users will have greater awareness of new features, bug fixes, and security fixes to the extensions used.

##### What do you need to do?

Extension authors should review their extensions and consider removing any custom logic previously implemented to notify users of new releases.

### [`v2.61.0`](https://github.com/cli/cli/releases/tag/v2.61.0): GitHub CLI 2.61.0

[Compare Source](cli/cli@v2.60.1...v2.61.0)

#### Ensure users understand consequences before making repository visibility changes

In `v2.61.0`, `gh repo edit` command has been enhanced to inform users about [consequences of changing visibility](https://gh.io/setting-repository-visibility) and ensure users are intentional before making irreversible changes:

1.  Interactive `gh repo edit` visibility change requires confirmation when changing from `public`, `private`, or `internal`
2.  Non-interactive `gh repo edit --visibility` change requires new `--accept-visibility-change-consequences` flag to confirm
3.  New content to inform users of consequences
    -   Incorporate [GitHub Docs content](https://gh.io/setting-repository-visibility) into help usage and interactive `gh repo edit` experience
    -   Expanded help usage to call out most concerning consequences
    -   Display repository star and watcher counts to understand impact before confirming

#### What's Changed

-   Add acceptance test for `project` command by [@&#8203;jtmcg](https://github.com/jtmcg) in cli/cli#9816
-   Add comprehensive testscript for `gh ruleset` by [@&#8203;andyfeller](https://github.com/andyfeller) in cli/cli#9815
-   Add comprehensive testscript for gh ext commandset by [@&#8203;andyfeller](https://github.com/andyfeller) in cli/cli#9810
-   Require visibility confirmation in `gh repo edit` by [@&#8203;andyfeller](https://github.com/andyfeller) in cli/cli#9845
-   Clean up skipped online tests for `gh attestation verify` by [@&#8203;malancas](https://github.com/malancas) in cli/cli#9838
-   `gh attestation verify` should only verify provenance attestations by default by [@&#8203;malancas](https://github.com/malancas) in cli/cli#9825
-   Set `dnf5` commands as default by [@&#8203;its-miroma](https://github.com/its-miroma) in cli/cli#9844
-   Fix verbiage for deleting workflow runs by [@&#8203;akx](https://github.com/akx) in cli/cli#9876
-   Bump github.com/creack/pty from 1.1.23 to 1.1.24 by [@&#8203;dependabot](https://github.com/dependabot) in cli/cli#9862
-   `gh attestation verify` policy enforcement refactor by [@&#8203;malancas](https://github.com/malancas) in cli/cli#9848
-   Simplify Sigstore verification result handling in `gh attestation verify` by [@&#8203;malancas](https://github.com/malancas) in cli/cli#9877
-   Print empty array for `gh cache list` when `--json` is provided by [@&#8203;williammartin](https://github.com/williammartin) in cli/cli#9883
-   Bump actions/attest-build-provenance from 1.4.3 to 1.4.4 by [@&#8203;dependabot](https://github.com/dependabot) in cli/cli#9884
-   Create the automatic key when specified with -i by [@&#8203;cmbrose](https://github.com/cmbrose) in cli/cli#9881
-   fix: `gh pr create -w`  ignore template flag by [@&#8203;nilvng](https://github.com/nilvng) in cli/cli#9863

#### New Contributors

-   [@&#8203;akx](https://github.com/akx) made their first contribution in cli/cli#9876
-   [@&#8203;nilvng](https://github.com/nilvng) made their first contribution in cli/cli#9863

**Full Changelog**: cli/cli@v2.60.1...v2.61.0

### [`v2.60.1`](https://github.com/cli/cli/releases/tag/v2.60.1): GitHub CLI 2.60.1

[Compare Source](cli/cli@v2.60.0...v2.60.1)

This is a small patch release to fix installing `gh` via `go install` which was broken with v2.60.0.

#### What's Changed

-   Update testscript to use hard fork by [@&#8203;williammartin](https://github.com/williammartin) in cli/cli#9821

**Full Changelog**: cli/cli@v2.60.0...v2.60.1

### [`v2.60.0`](https://github.com/cli/cli/releases/tag/v2.60.0): GitHub CLI 2.60.0

[Compare Source](cli/cli@v2.59.0...v2.60.0)

#### What's Changed

-   Add ArchivedAt field by [@&#8203;tsukasaI](https://github.com/tsukasaI) in cli/cli#9790
-   Include startedAt, completedAt in run steps data by [@&#8203;andyfeller](https://github.com/andyfeller) in cli/cli#9774
-   Adjust environment help for host and tokens by [@&#8203;williammartin](https://github.com/williammartin) in cli/cli#9809
-   Add handling of empty titles for Issues and MRs by [@&#8203;jtmcg](https://github.com/jtmcg) in cli/cli#9701
-   `LiveSigstoreVerifier.Verify` should error if no attestations are present by [@&#8203;phillmv](https://github.com/phillmv) in cli/cli#9742
-   `gh at verify` retries fetching attestations if it receives a 5xx by [@&#8203;phillmv](https://github.com/phillmv) in cli/cli#9797
-   Prevent local extension installations with invalid names and conflicts with core commands and other extensions by [@&#8203;BagToad](https://github.com/BagToad) in cli/cli#9794
-   Rewrite a sentence in CONTRIBUTING.md by [@&#8203;muzimuzhi](https://github.com/muzimuzhi) in cli/cli#9772
-   Use new GitHub preview terms in `working-with-us.md` by [@&#8203;BagToad](https://github.com/BagToad) in cli/cli#9800
-   Use new GitHub previews terminology in attestation commands' help docs by [@&#8203;BagToad](https://github.com/BagToad) in cli/cli#9799
-   Clarify in README that `gh` is supported on GitHub Enterprise Cloud by [@&#8203;BagToad](https://github.com/BagToad) in cli/cli#9805
-   build(deps): bump github.com/gabriel-vasile/mimetype from 1.4.5 to 1.4.6 by [@&#8203;dependabot](https://github.com/dependabot) in cli/cli#9752

##### Acceptance Test Changes

-   Add acceptance tests for `workflow`, `run`, and `cache` commands by [@&#8203;BagToad](https://github.com/BagToad) in cli/cli#9766
-   Add basic `api` acceptance tests by [@&#8203;BagToad](https://github.com/BagToad) in cli/cli#9770
-   Add acceptance tests for `release` commands by [@&#8203;BagToad](https://github.com/BagToad) in cli/cli#9771
-   Add acceptance tests for `org` and `ssh-key` commands by [@&#8203;BagToad](https://github.com/BagToad) in cli/cli#9812
-   Add acceptance tests for `gh auth` commands by [@&#8203;jtmcg](https://github.com/jtmcg) in cli/cli#9787
-   Add acceptance tests for `repo` commands by [@&#8203;jtmcg](https://github.com/jtmcg) in cli/cli#9783
-   Add acceptance tests for `search` command by [@&#8203;BagToad](https://github.com/BagToad) in cli/cli#9786
-   Add acceptance tests for `variable` commands by [@&#8203;andyfeller](https://github.com/andyfeller) in cli/cli#978
-   Add testscripts for gpg-key and label commands by [@&#8203;williammartin](https://github.com/williammartin) in cli/cli#9811
-   Use forked testscript for token redaction by [@&#8203;williammartin](https://github.com/williammartin) in cli/cli#9804
-   Add acceptance tests for `secret` commands by [@&#8203;andyfeller](https://github.com/andyfeller) in cli/cli#9782
-   Note token redaction in Acceptance test README by [@&#8203;williammartin](https://github.com/williammartin) in cli/cli#9813

#### New Contributors

-   [@&#8203;tsukasaI](https://github.com/tsukasaI) made their first contribution in cli/cli#9790

**Full Changelog**: cli/cli@v2.59.0...v2.60.0

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy40NDAuNyIsInVwZGF0ZWRJblZlciI6IjM3LjQ0MC43IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiXX0=-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external pull request originating outside of the CLI core team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants