Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proof of concept for flag-level disable auth check #9000

Merged
merged 3 commits into from Apr 29, 2024

Conversation

andyfeller
Copy link
Contributor

@andyfeller andyfeller commented Apr 25, 2024

Relates #8995

Building upon the existing command-level disable auth check logic, this commit adds flag-level disable auth check logic for any flag set with -b,--bundle flag of gh attestation verify being the first use case.

Subsequent commit to build out testing is needed as IsAuthCheckEnabled does not have tests.

Testing

  1. Build changes and setup temporary working directory

    andyfeller@Andys-MBP:cli/cli ‹andyfeller/flag-level-disableauth›$ make
    go build -trimpath -ldflags "-X github.com/cli/cli/v2/internal/build.Date=2024-04-25 -X github.com/cli/cli/v2/internal/build.Version=v2.48.0-9-g2d910406 " -o bin/gh ./cmd/gh
    
    andyfeller@Andys-MBP:cli/cli ‹andyfeller/flag-level-disableauth›$ mkdir tmp
    andyfeller@Andys-MBP:cli/cli ‹andyfeller/flag-level-disableauth›$ cd tmp 
  2. Download release artifact(s) built with attestation signatures captured

    andyfeller@Andys-MBP:cli/tmp ‹andyfeller/flag-level-disableauth›$ ../bin/gh release download v0.0.10 --repo advanced-security/gh-sbom
    andyfeller@Andys-MBP:cli/tmp ‹andyfeller/flag-level-disableauth*›$ ll
    total 152360
    -rw-r--r--  1 andyfeller  staff   5.8M Apr 25 09:41 android-amd64
    -rw-r--r--  1 andyfeller  staff   5.6M Apr 25 09:41 android-arm64
    -rw-r--r--  1 andyfeller  staff   5.6M Apr 25 09:41 darwin-amd64
    -rw-r--r--  1 andyfeller  staff   5.5M Apr 25 09:41 darwin-arm64
    -rw-r--r--  1 andyfeller  staff   5.0M Apr 25 09:41 freebsd-386
    -rw-r--r--  1 andyfeller  staff   5.3M Apr 25 09:41 freebsd-amd64
    -rw-r--r--  1 andyfeller  staff   5.1M Apr 25 09:41 freebsd-arm64
    -rw-r--r--  1 andyfeller  staff   5.1M Apr 25 09:41 linux-386
    -rw-r--r--  1 andyfeller  staff   5.3M Apr 25 09:41 linux-amd64
    -rw-r--r--  1 andyfeller  staff   5.2M Apr 25 09:41 linux-arm
    -rw-r--r--  1 andyfeller  staff   5.1M Apr 25 09:41 linux-arm64
    -rw-r--r--  1 andyfeller  staff   5.3M Apr 25 09:41 windows-386.exe
    -rw-r--r--  1 andyfeller  staff   5.5M Apr 25 09:41 windows-amd64.exe
    -rw-r--r--  1 andyfeller  staff   5.2M Apr 25 09:41 windows-arm64.exe
  3. Download artifact attestation bundle for artifact and verify

    andyfeller@Andys-MBP:cli/tmp ‹andyfeller/flag-level-disableauth*›$ ../bin/gh attestation download darwin-amd64 --repo advanced-security/gh-sbom
    Wrote attestations to file sha256:ab1bae8f19e92e1dce879373194627c1b322575618d13dd635572777d6df2437.jsonl.
    Any previous content has been overwritten
    
    The trusted metadata is now available at sha256:ab1bae8f19e92e1dce879373194627c1b322575618d13dd635572777d6df2437.jsonl
    
    
    andyfeller@Andys-MBP:cli/tmp ‹andyfeller/flag-level-disableauth*›$ ../bin/gh attestation verify darwin-amd64 --bundle sha256:ab1bae8f19e92e1dce879373194627c1b322575618d13dd635572777d6df2437.jsonl --repo advanced-security/gh-sbom
    Loaded digest sha256:ab1bae8f19e92e1dce879373194627c1b322575618d13dd635572777d6df2437 for file://darwin-amd64
    Loaded 2 attestations from sha256:ab1bae8f19e92e1dce879373194627c1b322575618d13dd635572777d6df2437.jsonl
    ✓ Verification succeeded!
    
    sha256:ab1bae8f19e92e1dce879373194627c1b322575618d13dd635572777d6df2437 was attested by:
    REPO                       PREDICATE_TYPE                  WORKFLOW                                        
    advanced-security/gh-sbom  https://slsa.dev/provenance/v1  .github/workflows/release.yml@refs/tags/v0.0.10
    advanced-security/gh-sbom  https://slsa.dev/provenance/v1  .github/workflows/release.yml@refs/tags/vtesting
  4. Logout of github.com

    andyfeller@Andys-MBP:cli/tmp ‹andyfeller/flag-level-disableauth*›$ ../bin/gh auth status
    staffship-01.ghe.com
      ✓ Logged in to staffship-01.ghe.com account andyfeller (keyring)
      - Active account: true
      - Git operations protocol: https
      - Token: gho_************************************
      - Token scopes: 'gist', 'read:org', 'repo', 'workflow'
    
    github.ghe.com
      ✓ Logged in to github.ghe.com account andyfeller (keyring)
      - Active account: true
      - Git operations protocol: https
      - Token: gho_************************************
      - Token scopes: 'gist', 'read:org', 'repo', 'workflow'
    
    github.com
      ✓ Logged in to github.com account andyfeller (keyring)
      - Active account: true
      - Git operations protocol: ssh
      - Token: gho_************************************
      - Token scopes: 'admin:public_key', 'gist', 'read:org', 'repo'
    
    andyfeller@Andys-MBP:cli/tmp ‹andyfeller/flag-level-disableauth*›$ ../bin/gh auth logout
    ? What account do you want to log out of? andyfeller (github.com)
    ✓ Logged out of github.com account andyfeller
    
    andyfeller@Andys-MBP:cli/tmp ‹andyfeller/flag-level-disableauth*›$ ../bin/gh auth status
    staffship-01.ghe.com
      ✓ Logged in to staffship-01.ghe.com account andyfeller (keyring)
      - Active account: true
      - Git operations protocol: https
      - Token: gho_************************************
      - Token scopes: 'gist', 'read:org', 'repo', 'workflow'
    
    github.ghe.com
      ✓ Logged in to github.ghe.com account andyfeller (keyring)
      - Active account: true
      - Git operations protocol: https
      - Token: gho_************************************
      - Token scopes: 'gist', 'read:org', 'repo', 'workflow'
  5. Verify that gh attestation verify -b does not require auth with flag

    andyfeller@Andys-MBP:cli/tmp ‹andyfeller/flag-level-disableauth*›$ ../bin/gh attestation verify darwin-amd64 --bundle sha256:ab1bae8f19e92e1dce879373194627c1b322575618d13dd635572777d6df2437.jsonl --repo advanced-security/gh-sbom
    Loaded digest sha256:ab1bae8f19e92e1dce879373194627c1b322575618d13dd635572777d6df2437 for file://darwin-amd64
    Loaded 2 attestations from sha256:ab1bae8f19e92e1dce879373194627c1b322575618d13dd635572777d6df2437.jsonl
    ✓ Verification succeeded!
    
    sha256:ab1bae8f19e92e1dce879373194627c1b322575618d13dd635572777d6df2437 was attested by:
    REPO                       PREDICATE_TYPE                  WORKFLOW                                        
    advanced-security/gh-sbom  https://slsa.dev/provenance/v1  .github/workflows/release.yml@refs/tags/v0.0.10
    advanced-security/gh-sbom  https://slsa.dev/provenance/v1  .github/workflows/release.yml@refs/tags/vtesting

Building upon the existing command-level disable auth check logic, this commit adds flag-level disable auth check logic
for any flag set with `-b,--bundle` flag of `gh attestation verify` being the first use case.

Subsequent commit to build out testing is needed as IsAuthCheckEnabled does not have tests.
Copy link
Contributor

@steiza steiza 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 like a workable alternative to #8995 to me!

@andyfeller
Copy link
Contributor Author

@steiza @phillmv : is the manual process I listed above how you would test the feature?

@williammartin : is there anything about these changes you'd like to see beyond adding tests around the various auth check annotation use cases?

@williammartin
Copy link
Member

TL;DR

Let's move forward with this PR, thanks!

Design thoughts

I appreciate the work you've done here and I think it's pretty clever. That said, for a few reasons I prefer a less abstracted approach as in #8995. I've mentioned this elsewhere but I think that tying the authentication check logic into the cobra lifecycle takes us in a less maintainable direction in the long run. Copying and slightly modifying parts of a comment I made elsewhere so that it's in our public record:


I think the auth checks are too tightly coupled to Cobra configuration and that the responsibility to make this decision should be owned closer to the business logic. From an architecture astronauting point of view, it's a leaky abstraction and though I don't expect we'll ever swap out cobra, that all the auth checks that the business logic depends upon would no longer be validated preconditions if we did, should give us a hint that it's not where it belongs. Furthermore we see that the root command has become knowledgable about gh codespaces with some hard to understand logic which should be suspicious.

From a less theoretical point of view, this knowledge living in Cobra configuration makes it hard for the business logic to be specific about when it matters, as we've discovered with this offline verification issue. Additionally, the current situation causes spooky action at a distance and I would argue the situation that attestation is facing right now is a direct result of that. Had we looked at another command and seen something like:

func (c MyCommand) Run() error {
    if err := c.SharedActor.EnsureAuthenticated(); err != nil {
       return err
    }
}

We probably would have realised pretty quickly that authed / not authed was something to look at more closely. I'm not suggesting ^ is the solution, just an indication of code that would have acted as a beacon.


To call out a specific example, imagine a command that doesn't know whether authentication is required until some state has been evaluated.

All that said, I'm happy to move forward with this PR (plus tests) since you are keen on this approach and the risk is low. Really I just wanted a place to capture thoughts should we run into a situation where we wanted to revisit this decision, and to serve as a mental trigger when we come to thinking about other places where command level auth checks are not sufficient (e.g. extension install of public extensions).

@andyfeller
Copy link
Contributor Author

andyfeller commented Apr 29, 2024

Firstly, I want to say I completely agree with you:

I think the auth checks are too tightly coupled to Cobra configuration and that the responsibility to make this decision should be owned closer to the business logic.

Cobra is / should be merely an invocation layer handling flags and arguments to application code while whether authentication is necessary is an application concern. From a long term goal, I think refactoring the code to ensure application code is responsible for whether authentication is required makes sense.

Secondly, I don't think that work is trivial in the short term, necessitating a now solution until we get to the later solution

This draft was only intended as a now solution because authentication is tightly coupled to Cobra event hooks and I couldn't think of a simpler way to add support without significantly refactoring commands and the logic around Cobra event hooks:

cli/pkg/cmd/root/root.go

Lines 73 to 86 in 7d432bc

PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// require that the user is authenticated before running most commands
if cmdutil.IsAuthCheckEnabled(cmd) && !cmdutil.CheckAuth(cfg) {
parent := cmd.Parent()
if parent != nil && parent.Use == "codespace" {
fmt.Fprintln(io.ErrOut, "To get started with GitHub CLI, please run: gh auth login -s codespace")
} else {
fmt.Fprint(io.ErrOut, authHelp())
}
return &AuthError{}
}
return nil
},
}

This commit adds various test cases around whether a command will require authentication based on Cobra annotation metadata.
@andyfeller andyfeller marked this pull request as ready for review April 29, 2024 14:03
@andyfeller andyfeller requested review from a team as code owners April 29, 2024 14:03
@cliAutomation cliAutomation added the external pull request originating outside of the CLI core team label Apr 29, 2024
@cliAutomation cliAutomation added this to Needs review 🤔 in The GitHub CLI Apr 29, 2024
Copy link
Member

@williammartin williammartin left a comment

Choose a reason for hiding this comment

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

One test addition I think would be useful

pkg/cmd/attestation/verify/verify.go Show resolved Hide resolved
cmd, err := tt.init()
require.NoError(t, err)

// IsAuthCheckEnabled assumes commands under test are subcommands
Copy link
Member

Choose a reason for hiding this comment

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

Lol not suspicious of coupling at all.

Thanks to @williammartin, this completes the PR by ensuring the actual feature this new logic was added for actually works as expected :D
Copy link
Member

@williammartin williammartin left a comment

Choose a reason for hiding this comment

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

Before (without --bundle)

GH_CONFIG_DIR=/tmp/test/gh gh attestation verify oci://ghcr.io/phillmv/arquivo -o phillmv                     
To get started with GitHub CLI, please run:  gh auth login
Alternatively, populate the GH_TOKEN environment variable with a GitHub API authentication token.

After (without --bundle)

GH_CONFIG_DIR=/tmp/test/gh ~/workspace/cli/bin/gh attestation verify oci://ghcr.io/phillmv/arquivo -o phillmv 
To get started with GitHub CLI, please run:  gh auth login
Alternatively, populate the GH_TOKEN environment variable with a GitHub API authentication token.

Before (with --bundle)

GH_CONFIG_DIR=/tmp/test/gh gh attestation verify oci://ghcr.io/phillmv/arquivo -o phillmv --bundle bundle.json 
To get started with GitHub CLI, please run:  gh auth login
Alternatively, populate the GH_TOKEN environment variable with a GitHub API authentication token.

After (with --bundle)

GH_CONFIG_DIR=/tmp/test/gh ~/workspace/cli/bin/gh attestation verify oci://ghcr.io/phillmv/arquivo -o phillmv --bundle bundle.json
Loaded digest sha256:5936c74c8999e9fd50ca0658f378a5d3f8492fb04bd77b952942fdbba4d038bb for oci://ghcr.io/phillmv/arquivo
✗ Loading attestations from oci://ghcr.io/phillmv/arquivo failed

Error: bundle could not be loaded from JSON file: open bundle.json: no such file or directory

We can see in this last case that although the bundle didn't exist (expected error) we did not have the auth check.

LGTM!

@andyfeller andyfeller merged commit 68dfd87 into trunk Apr 29, 2024
16 checks passed
@andyfeller andyfeller deleted the andyfeller/flag-level-disableauth branch April 29, 2024 16:15
alexcb pushed a commit to earthly/earthly that referenced this pull request May 7, 2024
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [cli/cli](https://togithub.com/cli/cli) | minor | `v2.48.0` ->
`v2.49.0` |

---

### Release Notes

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

### [`v2.49.0`](https://togithub.com/cli/cli/releases/tag/v2.49.0):
GitHub CLI 2.49.0

[Compare Source](https://togithub.com/cli/cli/compare/v2.48.0...v2.49.0)

#### Support for GitHub Artifact Attestations

`v2.49.0` release introduces the `attestation` command set for
downloading and verifying attestations about artifacts built in GitHub
Actions! This is part of the larger Artifact Attestations initiative. An
artifact attestation is a piece of cryptographically signed metadata
that is generated as part of your artifact build process. These
attestations bind artifacts to the details of the workflow run that
produced them, and allow you to guarantee the integrity and provenance
of any artifact built in GitHub Actions.

```shell

### Verify a local artifact
gh attestation verify artifact.bin -o <your org>

### Verify a local artifact against a local artifact attestation
gh attestation verify artifact.bin -b ./artifact-v0.0.1-bundle.json -o <your org>

### Verify an OCI image
gh attestation verify oci://ghcr.io/foo/bar:latest -o <your org>

### Download artifact attestations
gh attestation download artifact.bin -o <your org>
```

To get started, check out gh help attestation. You can also use the `gh
at <command>` alias for short.

#### What's Changed

- Improve gh run rerun docs by
[@&#8203;sochotnicky](https://togithub.com/sochotnicky) in
[cli/cli#8969
- build(deps): bump golang.org/x/net from 0.21.0 to 0.23.0 by
[@&#8203;dependabot](https://togithub.com/dependabot) in
[cli/cli#8981
- Update `sigstore-go` dependency to v0.3.0 by
[@&#8203;malancas](https://togithub.com/malancas) in
[cli/cli#8977
- `gh attestation tuf-root-verify` offline test fix by
[@&#8203;malancas](https://togithub.com/malancas) in
[cli/cli#8975
- Update `gh attestation verify` output by
[@&#8203;malancas](https://togithub.com/malancas) in
[cli/cli#8991
- build(deps): bump google.golang.org/grpc from 1.62.1 to 1.62.2 by
[@&#8203;dependabot](https://togithub.com/dependabot) in
[cli/cli#8989
- Remove `Hidden` flag from `gh attestation` command by
[@&#8203;malancas](https://togithub.com/malancas) in
[cli/cli#8998
- Add colon for `gh secret set` by
[@&#8203;NeroBlackstone](https://togithub.com/NeroBlackstone) in
[cli/cli#9004
- Improve errors when loading bundle locally fails by
[@&#8203;williammartin](https://togithub.com/williammartin) in
[cli/cli#8996
- Support offline mode for `gh attestation verify` by
[@&#8203;steiza](https://togithub.com/steiza) in
[cli/cli#8997
- Add `projectsV2` to JSON fields of `gh repo` commands by
[@&#8203;babakks](https://togithub.com/babakks) in
[cli/cli#9007
- Support long URLs in `gh repo clone` by
[@&#8203;babakks](https://togithub.com/babakks) in
[cli/cli#9008
- Fix issue with closing pager stream by
[@&#8203;babakks](https://togithub.com/babakks) in
[cli/cli#9020
- proof of concept for flag-level disable auth check by
[@&#8203;andyfeller](https://togithub.com/andyfeller) in
[cli/cli#9000
- Be more general with attestation host checks by
[@&#8203;williammartin](https://togithub.com/williammartin) in
[cli/cli#9019
- Add beta designation on attestation command set by
[@&#8203;andyfeller](https://togithub.com/andyfeller) in
[cli/cli#9022
- Tweaked gh attestation help strings to generate nicer cli manual site.
by [@&#8203;phillmv](https://togithub.com/phillmv) in
[cli/cli#9025
- Update cli/go-gh to v2.9.0 by
[@&#8203;andyfeller](https://togithub.com/andyfeller) in
[cli/cli#9023
- Document repo clone protocol behaviour by
[@&#8203;williammartin](https://togithub.com/williammartin) in
[cli/cli#9030

#### New Contributors

- [@&#8203;sochotnicky](https://togithub.com/sochotnicky) made their
first contribution in
[cli/cli#8969
- [@&#8203;NeroBlackstone](https://togithub.com/NeroBlackstone) made
their first contribution in
[cli/cli#9004
- [@&#8203;phillmv](https://togithub.com/phillmv) made their first
contribution in
[cli/cli#9025

**Full Changelog**: cli/cli@v2.48.0...v2.49.0

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 4pm on monday" (UTC), Automerge
- At any time (no schedule defined).

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

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

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

---

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

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/earthly/earthly).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4zNDAuMTAiLCJ1cGRhdGVkSW5WZXIiOiIzNy4zNDAuMTAiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbInJlbm92YXRlIl19-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
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
No open projects
The GitHub CLI
  
Needs review 🤔
Development

Successfully merging this pull request may close these issues.

None yet

4 participants