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

SLSA 1.0 Predicate for npm provenance #798

Open
feelepxyz opened this issue Apr 4, 2023 · 7 comments
Open

SLSA 1.0 Predicate for npm provenance #798

feelepxyz opened this issue Apr 4, 2023 · 7 comments

Comments

@feelepxyz
Copy link
Contributor

feelepxyz commented Apr 4, 2023

👋 I've been looking at the v1 actions spec to see what we want to include in the provenance statement generated by the npm CLI in an untrusted workflow (when running npm publish --provenance).

I'm currently thinking we should omit the external parameters deployment, release, inputs, vars as we have no way of telling if these have been forged or not. Also, I don't think there's a way to extract vars without having access to the github context, which the npm CLI does not have.

I'm thinking the predicate would look like this, were all properties can be checked against the new Fulcio cert extensions:

{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [{
    "name": "pkg:npm/sigstore@1.2.0",
    "digest": {
      "sha512": "16bf7e5b59e40522190a425047b8c39ffcc8d145cdb15a69fbb9834240a764e2311bda7ac8d5c1c7dc67b47b1f532607139e570e4915577fab61bae4cc079eb0"
    }
  }],
  "predicateType": "https://slsa.dev/provenance/v1",
  "predicate": {
    "buildDefinition": {
      "buildType": "https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1",
      "externalParameters": {
        "workflow": {
          "ref": "refs/heads/main",
          "repository": "https://github.com/sigstore/sigstore-js",
          "path": ".github/workflow/release.yml"
        }
      },
      "systemParameters": {
        "github": {
          "event_name": "push",
          "repository_id": "495574555",
          "repository_owner_id": "71096353"
        }
      },
      "resolvedDependencies": [
        {
          "uri": "git+https://github.com/sigstore/sigstore-js@refs/heads/main",
          "digest": {
            "gitCommit": "5b8c0801d1f5d105351a403f58c38269de93f680"
          }
        }
      ]
    },
    "runDetails": {
      "builder": {
        "id": "https://github.com/actions/runner/github-hosted"
      },
      "metadata": {
        "invocationId": "https://github.com/sigstore/sigstore-js/actions/runs/1536140711/attempts/1",
        "startedOn": "2023-01-01T12:34:56Z"
      }
    }
  }
}

Does this seem reasonable and look right?

cc @ianlewis @MarkLodato @laurentsimon @kommendorkapten @bdehamer

@kommendorkapten
Copy link

To populate the content of any of the external parameters: deployment, release, inputs you would also need access to the GitHub context? Or are they values available via environment variables?

But as they are forgeable when running in a normal workflow, I support the idea of not populating them for npm.

But from a general perspective, it makes sense to have them if they could be added in a non-forgeable, so I don't think the linked v1 actions spec has to be updated.

@feelepxyz
Copy link
Contributor Author

Or are they values available via environment variables?

You can fish these out by parsing the event.json file at GITHUB_EVENT_PATH which should contain these bits.

But from a general perspective, it makes sense to have them if they could be added in a non-forgeable

💯 yeah for sure makes sense from a trusted/reusable workflow for example.

so I don't think the linked v1 actions spec has to be updated.

Ah yes, the actions spec is only for a untrusted/top-level workflow right?

@MarkLodato
Copy link
Member

<aside>
I'm going to state a controversial opinion: the Fulcio cert should contain an embedded, JSON-encoded SLSA Provenance predicate rather than a bunch of separate fields. The current design is that the cert is the (GitHub-attested) provenance, and then this provenance is re-encoded in the payload and signed again, but mixed with unattested fields (or really fields attested by the workload, not GitHub). That model is hard to understand and leads to conflicts like what fields you should or should not put in the provenance. IMO it would be much cleaner to have separate layers to make it obvious what party attests to what information.
</aside>

I think the original question can be rephrased as follows: is it OK for SLSA L2 provenance to contain external parameters that are not guaranteed by the build system?

The conflict is in the following Provenance is authentic sub-requirements, specifically those labeled (3) and (4) below:

  1. The data in the provenance MUST be obtained from the build service
  2. The build system MUST have some security control to prevent tenants from tampering with the provenance [but with no minimum strength]
  3. Any field that is not marked as REQUIRED for Build L2 [...] MAY be generated by a tenant of the build system
  4. There MAY be external parameters that are not sufficiently captured in the provenance.

The situation in the original post is that:

  • The build system attests to some but not all of the external parameters, which is explicitly permitted by (4).
  • It is clearly permissible to omit the unattested external parameters through a straightforward reading of (4)
  • But is it permissible by (3) to add additional external parameters that are not attested by the build system, if it is clearly explained in the builder.id documentation what is attested by the build system and what is not?

I don't have an opinion right away, but want to see if I can first precisely capture the problem in terms of the specification.

@laurentsimon
Copy link
Contributor

"buildType": "https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1",

Do you want to add a self-hosted vs github-hosted? I'm fine either way.

But as they are forgeable when running in a normal workflow, I support the idea of not populating them for npm.

+1 from me too

@ianlewis
Copy link
Member

ianlewis commented Apr 6, 2023

But as they are forgeable when running in a normal workflow, I support the idea of not populating them for npm.

👍

"buildType": "https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1",

Do you want to add a self-hosted vs github-hosted? I'm fine either way.

BTW, this is what is suggested in the "official" community repo for GHA.
https://github.com/slsa-framework/github-actions-buildtypes/tree/main/workflow/v1#description

I wonder if this isn't something that shouldn't be captured in the builder ID rather than the buildType? The fact that it's github-hosted seems to be captured there at least, though perhaps this should also reflect the fact that it's coming from the npm cli?

"id": "https://github.com/actions/runner/github-hosted"

@laurentsimon
Copy link
Contributor

I wonder if this isn't something that shouldn't be captured in the builder ID rather than the buildType? The fact that it's github-hosted seems to be captured there at least, though perhaps this should also reflect the fact that it's coming from the npm cli?

+1, I got confused. It is in the builder.id, you're correct. The example uses it as well. Ignore my previous comment.

@feelepxyz
Copy link
Contributor Author

FYI we've got a PR up for this here: npm/cli#6613

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Untriaged
Development

No branches or pull requests

5 participants