Skip to content

Commit

Permalink
export new createVerifier function (#559)
Browse files Browse the repository at this point in the history
* export new initBasicVerifier function

Signed-off-by: Brian DeHamer <bdehamer@github.com>

* basicVerifier → createVerifier

Signed-off-by: Brian DeHamer <bdehamer@github.com>

---------

Signed-off-by: Brian DeHamer <bdehamer@github.com>
  • Loading branch information
bdehamer committed Jun 28, 2023
1 parent 3a902bc commit fbfb315
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/silly-turtles-pull.md
@@ -0,0 +1,5 @@
---
'sigstore': minor
---

Exports new `createVerifier` function
5 changes: 5 additions & 0 deletions packages/client/src/__tests__/index.test.ts
Expand Up @@ -22,12 +22,17 @@ describe('sigstore', () => {
// 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 sigstore utils', () => {
Expand Down
63 changes: 58 additions & 5 deletions packages/client/src/__tests__/sigstore.test.ts
Expand Up @@ -13,6 +13,7 @@ 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.
*/
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import {
Bundle,
HashAlgorithm,
Expand All @@ -22,14 +23,16 @@ import {
X509CertificateChain,
} from '@sigstore/protobuf-specs';
import { TUFError } from '@sigstore/tuf';
import { fromPartial } from '@total-typescript/shoehorn';
import mocktuf, { Target } from '@tufjs/repo-mock';
import { PolicyError, VerificationError } from '../error';
import { Signer } from '../sign';
import { attest, sign, tuf, verify } from '../sigstore';
import { attest, createVerifier, sign, tuf, verify } from '../sigstore';
import { SerializedBundle } from '../types/sigstore';
import bundles from './__fixtures__/bundles';
import { trustedRoot } from './__fixtures__/trust';

import type { VerifyOptions } from '../config';
import type { TUFOptions, VerifyOptions } from '../config';

jest.mock('../sign');

Expand Down Expand Up @@ -317,25 +320,75 @@ describe('#verify', () => {
});
});

describe('tuf', () => {
describe('#createVerifier', () => {
let tufRepo: ReturnType<typeof mocktuf> | undefined;
let options: VerifyOptions | undefined;
let tufOptions: VerifyOptions | undefined;

const trustedRootJSON = JSON.stringify(TrustedRoot.toJSON(trustedRoot));
const target: Target = {
name: 'trusted_root.json',
content: Buffer.from(trustedRootJSON),
};

beforeEach(() => {
tufRepo = mocktuf(target, { metadataPathPrefix: '' });
options = {
tufOptions = {
tufMirrorURL: tufRepo.baseURL,
tufCachePath: tufRepo.cachePath,
};
});

afterEach(() => tufRepo?.teardown());

it('returns a object', async () => {
const verifier = await createVerifier(tufOptions!);
expect(verifier).toBeInstanceOf(Object);
});

describe('when the bundle is valid', () => {
const bundle: SerializedBundle = fromPartial(
bundles.dsse.valid.withSigningCert
);

it('does not throw an error when invoked', async () => {
const verifier = await createVerifier(tufOptions!);
expect(verifier.verify(bundle)).toBeUndefined();
});
});

describe('when the bundle is invalid', () => {
const bundle: SerializedBundle = fromPartial(
bundles.dsse.invalid.badSignature
);

it('throws an error when invoked', async () => {
const verifier = await createVerifier(tufOptions!);
expect(() => {
verifier.verify(bundle);
}).toThrowError(VerificationError);
});
});
});

describe('tuf', () => {
let tufRepo: ReturnType<typeof mocktuf> | undefined;
let options: TUFOptions | undefined;

const target: Target = {
name: 'foo',
content: 'bar',
};

beforeEach(() => {
tufRepo = mocktuf(target, { metadataPathPrefix: '' });
options = {
tufMirrorURL: tufRepo.baseURL,
tufCachePath: tufRepo.cachePath,
};
});

afterEach(() => tufRepo?.teardown());

describe('getTarget', () => {
describe('when the target exists', () => {
it('returns the target', async () => {
Expand Down
4 changes: 4 additions & 0 deletions packages/client/src/config.ts
Expand Up @@ -68,6 +68,10 @@ export type VerifyOptions = {
} & TLogOptions &
TUFOptions;

export type CreateVerifierOptions = {
keySelector?: KeySelector;
} & TUFOptions;

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

Expand Down
25 changes: 25 additions & 0 deletions packages/client/src/sigstore.ts
Expand Up @@ -81,6 +81,31 @@ export async function verify(
return verifier.verify(deserializedBundle, opts, payload);
}

export interface BundleVerifier {
verify(bundle: sigstore.SerializedBundle): void;
}

export async function createVerifier(
options: config.CreateVerifierOptions
): Promise<BundleVerifier> {
const trustedRoot = await tuf.getTrustedRoot({
mirrorURL: options.tufMirrorURL,
rootPath: options.tufRootPath,
cachePath: options.tufCachePath,
retry: options.retry ?? config.DEFAULT_RETRY,
timeout: options.timeout ?? config.DEFAULT_TIMEOUT,
});
const verifier = new Verifier(trustedRoot, options.keySelector);
const verifyOpts = config.artifactVerificationOptions(options);

return {
verify: (bundle: sigstore.SerializedBundle): void => {
const deserializedBundle = sigstore.bundleFromJSON(bundle);
return verifier.verify(deserializedBundle, verifyOpts);
},
};
}

const tufUtils = {
client: (options: config.TUFOptions = {}): Promise<tuf.TUF> => {
return tuf.initTUF({
Expand Down

0 comments on commit fbfb315

Please sign in to comment.