Skip to content

Commit

Permalink
flatten public interface of client package (#694)
Browse files Browse the repository at this point in the history
Signed-off-by: Brian DeHamer <bdehamer@github.com>
  • Loading branch information
bdehamer committed Aug 17, 2023
1 parent faca7de commit 829e123
Show file tree
Hide file tree
Showing 16 changed files with 148 additions and 152 deletions.
5 changes: 5 additions & 0 deletions .changeset/angry-fireants-smile.md
@@ -0,0 +1,5 @@
---
'sigstore': major
---

Replaces the exported `sigstore` object with individual functions/types
2 changes: 1 addition & 1 deletion packages/cli/src/commands/attest.ts
@@ -1,7 +1,7 @@
import color from '@oclif/color';
import { Args, Command, Flags } from '@oclif/core';
import fs from 'fs/promises';
import { sigstore } from 'sigstore';
import * as sigstore from 'sigstore';
import { OAuthIdentityProvider } from '../oauth';

import type { IdentityProvider } from 'sigstore';
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/commands/verify.ts
@@ -1,6 +1,6 @@
import { Args, Command, Flags } from '@oclif/core';
import fs from 'fs/promises';
import { sigstore } from 'sigstore';
import * as sigstore from 'sigstore';

export default class Verify extends Command {
static override description = 'verify the supplied .sigstore bundle file';
Expand Down Expand Up @@ -43,7 +43,7 @@ export default class Verify extends Command {
.readFile(args.bundle)
.then((data) => JSON.parse(data.toString()));

return sigstore.verify(bundle, undefined, options).then(() => {
return sigstore.verify(bundle, options).then(() => {
this.logToStderr('Verification succeeded');
return { verified: true };
});
Expand Down
68 changes: 33 additions & 35 deletions packages/client/README.md
Expand Up @@ -6,9 +6,9 @@ and verify any file.

## Features

* Support for signing using an OpenID Connect identity
* Support for publishing signatures to a [Rekor][1] instance
* Support for verifying Sigstore bundles
- Support for signing using an OpenID Connect identity
- Support for publishing signatures to a [Rekor][1] instance
- Support for verifying Sigstore bundles

## Prerequisites

Expand Down Expand Up @@ -140,11 +140,11 @@ library. It also lists which `sigstore` versions were shipped with different
## Usage

```javascript
const { sigstore } = require('sigstore')
const { attest, verify } = require('sigstore');
```

```javascript
import { sigstore } from 'sigstore'
import { attest, verify } from 'sigstore';
```

### sign(payload[, options])
Expand All @@ -153,47 +153,46 @@ Generates a Sigstore signature for the supplied payload. Returns a
[Sigstore bundle][2] containing the signature and the verification material
necessary to verify the signature.

* `payload` `<Buffer>`: The bytes of the artifact to be signed.
* `options` `<Object>`
* `fulcioURL` `<string>`: The base URL of the Fulcio instance to use for retrieving the signing certificate. Defaults to `'https://fulcio.sigstore.dev'`.
* `rekorURL` `<string>`: The base URL of the Rekor instance to use when adding the signature to the transparency log. Defaults to `'https://rekor.sigstore.dev'`.
* `tsaServerURL` `<string>`: The base URL of the Timestamp Authority instance to use when requesting a signed timestamp. If omitted, no timestamp will be requested.
* `tlogUpload` `<boolean>`: Flag indicating whether or not the signature should be recorded on the Rekor transparency log. Defaults to `true`.
* `identityToken` `<string>`: The OIDC token identifying the signer. If no explicit token is supplied, an attempt will be made to retrieve one from the environment. This config cannot be used with `identityProvider`.
* `identityProvider` `<IdentityProvider>`: Object which implements `getToken: () => Promise<string>`. The supplied provider will be used to retrieve an OIDC token. If no provider is supplied, an attempt will be made to retrieve an OIDC token from the environment. This config cannot be used with `identityToken`.
- `payload` `<Buffer>`: The bytes of the artifact to be signed.
- `options` `<Object>`
- `fulcioURL` `<string>`: The base URL of the Fulcio instance to use for retrieving the signing certificate. Defaults to `'https://fulcio.sigstore.dev'`.
- `rekorURL` `<string>`: The base URL of the Rekor instance to use when adding the signature to the transparency log. Defaults to `'https://rekor.sigstore.dev'`.
- `tsaServerURL` `<string>`: The base URL of the Timestamp Authority instance to use when requesting a signed timestamp. If omitted, no timestamp will be requested.
- `tlogUpload` `<boolean>`: Flag indicating whether or not the signature should be recorded on the Rekor transparency log. Defaults to `true`.
- `identityToken` `<string>`: The OIDC token identifying the signer. If no explicit token is supplied, an attempt will be made to retrieve one from the environment. This config cannot be used with `identityProvider`.
- `identityProvider` `<IdentityProvider>`: Object which implements `getToken: () => Promise<string>`. The supplied provider will be used to retrieve an OIDC token. If no provider is supplied, an attempt will be made to retrieve an OIDC token from the environment. This config cannot be used with `identityToken`.

### attest(payload, payloadType[, options])

Generates a Sigstore signature for the supplied in-toto statement. Returns a
[Sigstore bundle][2] containing the [DSSE][3]-wrapped statement and signature
as well as the verification material necessary to verify the signature.

* `payload` `<Buffer>`: The bytes of the statement to be signed.
* `payloadType` `<string>`: MIME or content type describing the statement to be signed.
* `options` `<Object>`
* `fulcioURL` `<string>`: The base URL of the Fulcio instance to use for retrieving the signing certificate. Defaults to `'https://fulcio.sigstore.dev'`.
* `rekorURL` `<string>`: The base URL of the Rekor instance to use when adding the signature to the transparency log. Defaults to `'https://rekor.sigstore.dev'`.
* `tsaServerURL` `<string>`: The base URL of the Timestamp Authority instance to use when requesting a signed timestamp. If omitted, no timestamp will be requested.
* `tlogUpload` `<boolean>`: Flag indicating whether or not the signed statement should be recorded on the Rekor transparency log. Defaults to `true`.
* `identityToken` `<string>`: The OIDC token identifying the signer. If no explicit token is supplied, an attempt will be made to retrieve one from the environment. This config cannot be used with `identityProvider`.
* `identityProvider` `<IdentityProvider>`: Object which implements `getToken: () => Promise<string>`. The supplied provider will be used to retrieve an OIDC token. If no provider is supplied, an attempt will be made to retrieve an OIDC token from the environment. This config cannot be used with `identityToken`.

- `payload` `<Buffer>`: The bytes of the statement to be signed.
- `payloadType` `<string>`: MIME or content type describing the statement to be signed.
- `options` `<Object>`
- `fulcioURL` `<string>`: The base URL of the Fulcio instance to use for retrieving the signing certificate. Defaults to `'https://fulcio.sigstore.dev'`.
- `rekorURL` `<string>`: The base URL of the Rekor instance to use when adding the signature to the transparency log. Defaults to `'https://rekor.sigstore.dev'`.
- `tsaServerURL` `<string>`: The base URL of the Timestamp Authority instance to use when requesting a signed timestamp. If omitted, no timestamp will be requested.
- `tlogUpload` `<boolean>`: Flag indicating whether or not the signed statement should be recorded on the Rekor transparency log. Defaults to `true`.
- `identityToken` `<string>`: The OIDC token identifying the signer. If no explicit token is supplied, an attempt will be made to retrieve one from the environment. This config cannot be used with `identityProvider`.
- `identityProvider` `<IdentityProvider>`: Object which implements `getToken: () => Promise<string>`. The supplied provider will be used to retrieve an OIDC token. If no provider is supplied, an attempt will be made to retrieve an OIDC token from the environment. This config cannot be used with `identityToken`.

### verify(bundle[, payload][, options])

Verifies the signature in the supplied bundle.

* `bundle` `<Bundle>`: The Sigstore bundle containing the signature to be verified and the verification material necessary to verify the signature.
* `payload` `<Buffer>`: The bytes of the artifact over which the signature was created. Only necessary when the `sign` function was used to generate the signature since the Bundle does not contain any information about the artifact which was signed. Not required when the `attest` function was used to generate the Bundle.
* `options` `<Object>`
* `ctLogThreshold` `<number>`: The number of certificate transparency logs on which the signing certificate must appear. Defaults to `1`.
* `tlogThreshold` `<number>`: The number of transparency logs on which the signature must appear. Defaults to `1`.
* `certificateIssuer` `<string>`: Value that must appear in the signing certificate's issuer extension (OID 1.3.6.1.4.1.57264.1.1). Not verified if no value is supplied.
* `certificateIdentityEmail` `<string>`: Email address which must appear in the signing certificate's Subject Alternative Name (SAN) extension. Must be specified in conjunction with the `certificateIssuer` option. Takes precedence over the `certificateIdentityURI` option. Not verified if no value is supplied.
* `certificateIdentityURI` `<string>`: URI which must appear in the signing certificate's Subject Alternative Name (SAN) extension. Must be specified in conjunction with the `certificateIssuer` option. Ignored if the `certificateIdentityEmail` option is set. Not verified if no value is supplied.
* `certificateOIDs` `<Object>`: A collection of OID/value pairs which must be present in the certificate's extension list. Not verified if no value is supplied.
* `keySelector` `<Function>`: Callback invoked to retrieve the public key (as either `string` or `Buffer`) necessary to verify the bundle signature. Not used when the signature was generated from a Fulcio-issued signing certificate.
* `hint` `<String>`: The hint from the bundle used to identify the the signing key.
- `bundle` `<Bundle>`: The Sigstore bundle containing the signature to be verified and the verification material necessary to verify the signature.
- `payload` `<Buffer>`: The bytes of the artifact over which the signature was created. Only necessary when the `sign` function was used to generate the signature since the Bundle does not contain any information about the artifact which was signed. Not required when the `attest` function was used to generate the Bundle.
- `options` `<Object>`
- `ctLogThreshold` `<number>`: The number of certificate transparency logs on which the signing certificate must appear. Defaults to `1`.
- `tlogThreshold` `<number>`: The number of transparency logs on which the signature must appear. Defaults to `1`.
- `certificateIssuer` `<string>`: Value that must appear in the signing certificate's issuer extension (OID 1.3.6.1.4.1.57264.1.1). Not verified if no value is supplied.
- `certificateIdentityEmail` `<string>`: Email address which must appear in the signing certificate's Subject Alternative Name (SAN) extension. Must be specified in conjunction with the `certificateIssuer` option. Takes precedence over the `certificateIdentityURI` option. Not verified if no value is supplied.
- `certificateIdentityURI` `<string>`: URI which must appear in the signing certificate's Subject Alternative Name (SAN) extension. Must be specified in conjunction with the `certificateIssuer` option. Ignored if the `certificateIdentityEmail` option is set. Not verified if no value is supplied.
- `certificateOIDs` `<Object>`: A collection of OID/value pairs which must be present in the certificate's extension list. Not verified if no value is supplied.
- `keySelector` `<Function>`: Callback invoked to retrieve the public key (as either `string` or `Buffer`) necessary to verify the bundle signature. Not used when the signature was generated from a Fulcio-issued signing certificate.
- `hint` `<String>`: The hint from the bundle used to identify the the signing key.

## Credential Sources

Expand All @@ -212,7 +211,6 @@ for more details.
If the `SIGSTORE_ID_TOKEN` environment variable is set, it will use this to authenticate to Fulcio.
It is the callers responsibility to make sure that this token has the correct scopes.


[1]: https://github.com/sigstore/rekor
[2]: https://github.com/sigstore/protobuf-specs/blob/9b722b68a717778ba4f11543afa4ef93205ab502/protos/sigstore_bundle.proto#L63-L84
[3]: https://github.com/secure-systems-lab/dsse
Expand Down
Expand Up @@ -38,6 +38,7 @@ const validBundleWithSigningCert = {
},
],
},
publicKey: undefined,
tlogEntries: [
{
logIndex: '6751924',
Expand All @@ -48,6 +49,7 @@ const validBundleWithSigningCert = {
signedEntryTimestamp:
'MEQCIEzguFRaGzOpMw9JJGUfqSJQ11qlzpcyVCkZfZYPwpLCAiBzdU4LnjtVKYCfyoTImFh3OLFWeOKygtS47Z8fp1GYHg==',
},
inclusionProof: undefined,
canonicalizedBody:
'eyJhcGlWZXJzaW9uIjoiMC4wLjIiLCJraW5kIjoiaW50b3RvIiwic3BlYyI6eyJjb250ZW50Ijp7ImVudmVsb3BlIjp7InBheWxvYWRUeXBlIjoidGV4dC9wbGFpbiIsInNpZ25hdHVyZXMiOlt7InB1YmxpY0tleSI6IkxTMHRMUzFDUlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVU51ZWtORFFXbFhaMEYzU1VKQlowbFZWa2gzWldoUGRFZHVORXRUUkRGSU9GSkpOVGd4VFdaaWVXVjNkME5uV1VsTGIxcEplbW93UlVGM1RYY0tUbnBGVmsxQ1RVZEJNVlZGUTJoTlRXTXliRzVqTTFKMlkyMVZkVnBIVmpKTlVqUjNTRUZaUkZaUlVVUkZlRlo2WVZka2VtUkhPWGxhVXpGd1ltNVNiQXBqYlRGc1drZHNhR1JIVlhkSWFHTk9UV3BKZUUxVVFUUk5ha2t4VDBSQk1sZG9ZMDVOYWtsNFRWUkJORTFxVFhkUFJFRXlWMnBCUVUxR2EzZEZkMWxJQ2t0dldrbDZhakJEUVZGWlNVdHZXa2w2YWpCRVFWRmpSRkZuUVVWSFp6WklhbmgwTWxWT2FVb3hhM2QzY1RWWVVVbEpkMDFhYmtwbVZsRXpZa1l3TVhVS1drdDBaVTFrWTFZdk0zRm9RMjFYVDJWamIzaFNjWGR5WWxsVWMyaEhaemxPZVZoalFtSjJaVFo2UzNkYVZsUk1aWEZQUTBGVlVYZG5aMFpCVFVFMFJ3cEJNVlZrUkhkRlFpOTNVVVZCZDBsSVowUkJWRUpuVGxaSVUxVkZSRVJCUzBKblozSkNaMFZHUWxGalJFRjZRV1JDWjA1V1NGRTBSVVpuVVZVM1YzQlNDall3YzBOd1oyWjFNRFIzWTNOcWRrTkdlSFF3WmsxcmQwaDNXVVJXVWpCcVFrSm5kMFp2UVZVek9WQndlakZaYTBWYVlqVnhUbXB3UzBaWGFYaHBORmtLV2tRNGQwaDNXVVJXVWpCU1FWRklMMEpDVlhkRk5FVlNXVzVLY0ZsWE5VRmFSMVp2V1ZjeGJHTnBOV3BpTWpCM1RFRlpTMHQzV1VKQ1FVZEVkbnBCUWdwQlVWRmxZVWhTTUdOSVRUWk1lVGx1WVZoU2IyUlhTWFZaTWpsMFRESjRkbG95YkhWTU1qbG9aRmhTYjAxSlIwcENaMjl5UW1kRlJVRmtXalZCWjFGRENrSkljMFZsVVVJelFVaFZRVE5VTUhkaGMySklSVlJLYWtkU05HTnRWMk16UVhGS1MxaHlhbVZRU3pNdmFEUndlV2RET0hBM2J6UkJRVUZIUlZkWVkxSUtPRUZCUVVKQlRVRlNha0pGUVdsQ1VsUnlSMFUxV1RGRmJsbHVhV0ZLUWl0dWMzWTRPVlpoV1hnelVWcHFiMk5GYVc0emNqa3hkMlpyUVVsblRYTnpLd3BtYzNOMU5WTk1VV3R1TjFkRVZFdFlaMjkzTjFONFlraFpVMXBxTTNscmVFRnlWbTUxZWtWM1EyZFpTVXR2V2tsNmFqQkZRWGROUkdGQlFYZGFVVWw0Q2tGUWFsTkhaR1JNU1haNVZVMUhTV3RhSzNVMlNtaEZPWEF4VG1wME0yUkZkSGRaYTAxNFptNUZWakpyTjAxSU1VSldiWGhuT1ZCelNtcHhlV05tYVNzS1pVRkpkMFJoUzI0eVEyUlBlRXR6ZUdObldVNXBORWgyYVVWdVduRjRiV1ZFZVc4eVdVWkpkSHB3U0daSlRWRnRZMUpUYkRreFZXVlBVME00SzFCMVJ3cG5kMDFMQ2kwdExTMHRSVTVFSUVORlVsUkpSa2xEUVZSRkxTMHRMUzBLIiwic2lnIjoiVFVWVlEwbERWV2hCVm1WM1puZExiR3MxWmxaNmNGSkVWVkJvUlhjNVR6aEpNbkI0UXpWdVZHNVFabGxFUW5OUFFXbEZRVEJhUm5Gek9UbFJaMUk1YlVGMFJrMVhkRmR5VDJwdFZVTTBOM3BuWVc5dmJFdEpiMHhJTDA5M1pFMDkifV19LCJoYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiZGNiNDkyNTljODY2MDdjMzQ2MzVkYWJiNDQzMWYwNjVlOWE3YTczNDcwNGNiNzNmMGFhMGY2YWFhMzg5NmEwNCJ9LCJwYXlsb2FkSGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6IjY4ZTY1NmIyNTFlNjdlODM1OGJlZjg0ODNhYjBkNTFjNjYxOWYzZTdhMWE5ZjBlNzU4MzhkNDFmZjM2OGY3MjgifX19fQ==',
},
Expand All @@ -64,6 +66,7 @@ const validBundleWithSigningCert = {
},
],
},
messageSignature: undefined,
};

// Valid DSSE bundle signed with a public key
Expand Down
82 changes: 39 additions & 43 deletions packages/client/src/__tests__/index.test.ts
Expand Up @@ -13,47 +13,43 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { IdentityProvider, sigstore } from '..';

describe('sigstore', () => {
// This test is a bit of a hack to ensure that the types are exported
it('exports sigstore types', async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const bundle: sigstore.Bundle = {} as any;
expect(bundle).toBeDefined();

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const envelope: sigstore.Envelope = {} as any;
expect(envelope).toBeDefined();

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const signOptions: sigstore.SignOptions = {} as any;
expect(signOptions).toBeDefined();

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const verifyOptions: sigstore.VerifyOptions = {} as any;
expect(verifyOptions).toBeDefined();

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const identityProvider: IdentityProvider = {} as any;
expect(identityProvider).toBeDefined();

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const bundleVerifier: sigstore.BundleVerifier = {} as any;
expect(bundleVerifier).toBeDefined();
});

it('exports sigstore core functions', async () => {
expect(sigstore.attest).toBeInstanceOf(Function);
expect(sigstore.sign).toBeInstanceOf(Function);
expect(sigstore.verify).toBeInstanceOf(Function);
expect(sigstore.createVerifier).toBeInstanceOf(Function);
});

it('exports errors', () => {
expect(sigstore.InternalError).toBeInstanceOf(Object);
expect(sigstore.PolicyError).toBeInstanceOf(Object);
expect(sigstore.VerificationError).toBeInstanceOf(Object);
expect(sigstore.ValidationError).toBeInstanceOf(Object);
});
import { fromPartial } from '@total-typescript/shoehorn';
import * as sigstore from '..';

// This test is a bit of a hack to ensure that the types are exported
it('exports sigstore types', async () => {
const bundle: sigstore.Bundle = fromPartial({});
expect(bundle).toBeDefined();

const signOptions: sigstore.SignOptions = fromPartial({});
expect(signOptions).toBeDefined();

const verifyOptions: sigstore.VerifyOptions = fromPartial({});
expect(verifyOptions).toBeDefined();

const identityProvider: sigstore.IdentityProvider = fromPartial({});
expect(identityProvider).toBeDefined();

const bundleVerifier: sigstore.BundleVerifier = fromPartial({});
expect(bundleVerifier).toBeDefined();
});

it('exports sigstore core functions', async () => {
expect(sigstore.attest).toBeInstanceOf(Function);
expect(sigstore.sign).toBeInstanceOf(Function);
expect(sigstore.verify).toBeInstanceOf(Function);
expect(sigstore.createVerifier).toBeInstanceOf(Function);
});

it('exports errors', () => {
expect(sigstore.InternalError).toBeInstanceOf(Object);
expect(sigstore.PolicyError).toBeInstanceOf(Object);
expect(sigstore.VerificationError).toBeInstanceOf(Object);
expect(sigstore.ValidationError).toBeInstanceOf(Object);
expect(sigstore.TUFError).toBeInstanceOf(Object);
});

it('exports constants', () => {
expect(sigstore.DEFAULT_FULCIO_URL).toBeDefined();
expect(sigstore.DEFAULT_REKOR_URL).toBeDefined();
});
7 changes: 2 additions & 5 deletions packages/client/src/__tests__/sigstore.test.ts
Expand Up @@ -136,13 +136,10 @@ describe('#verify', () => {
};

describe('when everything in the bundle is valid', () => {
const bundle = bundles.signature.valid.withSigningCert;
const artifact = bundles.signature.artifact;
const bundle = bundles.dsse.valid.withSigningCert;

it('does not throw an error', async () => {
await expect(verify(bundle, artifact, tufOptions)).resolves.toBe(
undefined
);
await expect(verify(bundle, tufOptions)).resolves.toBe(undefined);
});
});

Expand Down
5 changes: 4 additions & 1 deletion packages/client/src/ca/verify/signer.ts
Expand Up @@ -38,7 +38,10 @@ export function verifySignerIdentity(
);

if (!signerVerified) {
throw new PolicyError('Certificate issued to untrusted signer');
throw new PolicyError({
code: 'UNTRUSTED_SIGNER_ERROR',
message: 'Certificate issued to untrusted signer',
});
}
}

Expand Down
16 changes: 4 additions & 12 deletions packages/client/src/config.ts
Expand Up @@ -31,12 +31,6 @@ import * as sigstore from './types/sigstore';
import type { FetchOptions, Retry } from './types/fetch';
import type { KeySelector } from './verify';

export type TUFOptions = {
tufMirrorURL?: string;
tufRootPath?: string;
tufCachePath?: string;
} & FetchOptions;

export type SignOptions = {
fulcioURL?: string;
identityProvider?: IdentityProvider;
Expand All @@ -54,12 +48,10 @@ export type VerifyOptions = {
certificateIdentityURI?: string;
certificateOIDs?: Record<string, string>;
keySelector?: KeySelector;
rekorURL?: string;
} & TUFOptions;

export type CreateVerifierOptions = {
keySelector?: KeySelector;
} & TUFOptions;
tufMirrorURL?: string;
tufRootPath?: string;
tufCachePath?: string;
} & FetchOptions;

export const DEFAULT_FULCIO_URL = 'https://fulcio.sigstore.dev';
export const DEFAULT_REKOR_URL = 'https://rekor.sigstore.dev';
Expand Down

0 comments on commit 829e123

Please sign in to comment.