diff --git a/.changeset/sharp-rabbits-fix.md b/.changeset/sharp-rabbits-fix.md new file mode 100644 index 000000000..484aa2513 --- /dev/null +++ b/.changeset/sharp-rabbits-fix.md @@ -0,0 +1,5 @@ +--- +"@sigstore/tuf": minor +--- + +Add support for caching metadata from multiple TUF repositories diff --git a/.github/workflows/smoke-test.yml b/.github/workflows/smoke-test.yml index 8b2144f4b..568e3f20e 100644 --- a/.github/workflows/smoke-test.yml +++ b/.github/workflows/smoke-test.yml @@ -74,9 +74,6 @@ jobs: - name: Retrieve TUF trusted root run: | wget "${SIGSTORE_URL}/1.root.json" - - name: Initialize local TUF cache - run: | - ./packages/cli/bin/run init --mirror ${SIGSTORE_URL} --root ./1.root.json --force - name: Create artifact to sign run: | echo -n "hello world" > artifact @@ -91,7 +88,10 @@ jobs: artifact - name: Verify bundle run: | - ./packages/cli/bin/run verify bundle.json + ./packages/cli/bin/run verify \ + --tuf-mirror-url ${SIGSTORE_URL} \ + --tuf-root-path ./1.root.json \ + bundle.json - name: Archive bundle if: success() || failure() uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v3 diff --git a/packages/client/src/__tests__/sigstore.test.ts b/packages/client/src/__tests__/sigstore.test.ts index 9b402ec75..769404567 100644 --- a/packages/client/src/__tests__/sigstore.test.ts +++ b/packages/client/src/__tests__/sigstore.test.ts @@ -24,6 +24,7 @@ import * as invalidBundles from './__fixtures__/bundles/invalid'; import * as validBundles from './__fixtures__/bundles/valid'; import { trustedRoot } from './__fixtures__/trust'; +import path from 'path'; import type { SignOptions, VerifyOptions } from '../config'; const fulcioURL = 'https://fulcio.example.com'; @@ -129,6 +130,7 @@ describe('#verify', () => { tufOptions = { tufMirrorURL: tufRepo.baseURL, tufCachePath: tufRepo.cachePath, + tufRootPath: path.join(tufRepo.cachePath, 'root.json'), certificateIssuer: 'https://github.com/login/oauth', }; }); @@ -243,6 +245,7 @@ describe('#createVerifier', () => { tufOptions = { tufMirrorURL: tufRepo.baseURL, tufCachePath: tufRepo.cachePath, + tufRootPath: path.join(tufRepo.cachePath, 'root.json'), }; }); diff --git a/packages/tuf/package.json b/packages/tuf/package.json index 4e2d88bfd..4bfeefc26 100644 --- a/packages/tuf/package.json +++ b/packages/tuf/package.json @@ -10,8 +10,7 @@ "test": "jest" }, "files": [ - "dist", - "store" + "dist" ], "author": "bdehamer@github.com", "license": "Apache-2.0", diff --git a/packages/tuf/src/__tests__/client.test.ts b/packages/tuf/src/__tests__/client.test.ts index 6143e7faf..21166c935 100644 --- a/packages/tuf/src/__tests__/client.test.ts +++ b/packages/tuf/src/__tests__/client.test.ts @@ -20,24 +20,44 @@ import os from 'os'; import path from 'path'; import { TUFClient, TUFOptions } from '../client'; import { TUFError } from '../error'; +import { REPO_SEEDS } from '../store'; describe('TUFClient', () => { - const rootPath = require.resolve( - '../../store/public-good-instance-root.json' - ); - describe('constructor', () => { - const cacheDir = path.join(os.tmpdir(), 'tuf-client-test'); - const mirrorURL = 'https://example.com'; + let rootSeedDir: string; + let rootPath: string; + + const repoName = 'example.com'; + const mirrorURL = `https://${repoName}`; + const cacheRoot = path.join(os.tmpdir(), 'tuf-client-test'); + const cacheDir = path.join(cacheRoot, repoName); const force = false; - afterEach(() => fs.rmSync(cacheDir, { recursive: true })); + + beforeEach(() => { + rootSeedDir = fs.mkdtempSync( + path.join(os.tmpdir(), 'tuf-client-test-seed') + ); + + rootPath = path.join(rootSeedDir, 'root-seed.json'); + fs.writeFileSync( + rootPath, + Buffer.from( + REPO_SEEDS['https://tuf-repo-cdn.sigstore.dev']['root.json'], + 'base64' + ) + ); + }); + + afterEach(() => { + fs.rmSync(cacheRoot, { recursive: true }); + fs.rmSync(rootSeedDir, { recursive: true }); + }); describe('when the cache directory does not exist', () => { it('creates the cache directory', () => { - new TUFClient({ cachePath: cacheDir, mirrorURL, rootPath, force }); + new TUFClient({ cachePath: cacheRoot, mirrorURL, rootPath, force }); expect(fs.existsSync(cacheDir)).toEqual(true); expect(fs.existsSync(path.join(cacheDir, 'root.json'))).toEqual(true); - expect(fs.existsSync(path.join(cacheDir, 'remote.json'))).toEqual(true); }); }); @@ -45,10 +65,6 @@ describe('TUFClient', () => { beforeEach(() => { fs.mkdirSync(cacheDir, { recursive: true }); fs.copyFileSync(rootPath, path.join(cacheDir, 'root.json')); - fs.writeFileSync( - path.join(cacheDir, 'remote.json'), - JSON.stringify({ mirror: mirrorURL }) - ); }); it('loads config from the existing directory without error', () => { @@ -59,45 +75,47 @@ describe('TUFClient', () => { }); }); + describe('when no explicit root.json is provided', () => { + describe('when the mirror URL does NOT match one of the embedded roots', () => { + const mirrorURL = 'https://oops.net'; + it('throws an error', () => { + expect( + () => new TUFClient({ cachePath: cacheDir, mirrorURL, force }) + ).toThrowWithCode(TUFError, 'TUF_INIT_CACHE_ERROR'); + }); + }); + + describe('when the mirror URL matches one of the embedded roots', () => { + const mirrorURL = 'https://tuf-repo-cdn.sigstore.dev'; + it('loads the embedded root.json', () => { + expect( + () => new TUFClient({ cachePath: cacheDir, mirrorURL, force }) + ).not.toThrow(); + }); + }); + }); + describe('when forcing re-initialization of an existing directory', () => { - const oldMirrorURL = mirrorURL; - const newMirrorURL = 'https://new.org'; const force = true; beforeEach(() => { fs.mkdirSync(cacheDir, { recursive: true }); - fs.copyFileSync(rootPath, path.join(cacheDir, 'root.json')); - fs.writeFileSync( - path.join(cacheDir, 'remote.json'), - JSON.stringify({ mirror: oldMirrorURL }) - ); + fs.writeFileSync(path.join(cacheDir, 'root.json'), 'oops'); }); it('initializes the client without error', () => { expect( () => - new TUFClient({ - cachePath: cacheDir, - mirrorURL: newMirrorURL, - rootPath, - force, - }) + new TUFClient({ cachePath: cacheRoot, mirrorURL, rootPath, force }) ).not.toThrow(); }); it('overwrites the existing values', () => { - new TUFClient({ - cachePath: cacheDir, - mirrorURL: newMirrorURL, - rootPath, - force, - }); + new TUFClient({ cachePath: cacheRoot, mirrorURL, rootPath, force }); - const remote = fs.readFileSync( - path.join(cacheDir, 'remote.json'), - 'utf-8' - ); - expect(JSON.parse(remote)).toEqual({ mirror: newMirrorURL }); + const root = fs.readFileSync(path.join(cacheDir, 'root.json'), 'utf-8'); + expect(root).toBeDefined(); + expect(root).not.toEqual('oops'); }); }); }); @@ -117,7 +135,7 @@ describe('TUFClient', () => { mirrorURL: tufRepo.baseURL, cachePath: tufRepo.cachePath, retry: false, - rootPath, + rootPath: path.join(tufRepo.cachePath, 'root.json'), force: false, }; }); diff --git a/packages/tuf/src/__tests__/index.test.ts b/packages/tuf/src/__tests__/index.test.ts index 570fcbf81..dad425d19 100644 --- a/packages/tuf/src/__tests__/index.test.ts +++ b/packages/tuf/src/__tests__/index.test.ts @@ -17,6 +17,7 @@ limitations under the License. import { TrustedRoot } from '@sigstore/protobuf-specs'; import mocktuf, { Target } from '@tufjs/repo-mock'; import fs from 'fs'; +import path from 'path'; import { TUF, TUFError, TUFOptions, getTrustedRoot, initTUF } from '..'; import { TUFClient } from '../client'; @@ -73,7 +74,7 @@ describe('getTrustedRoot', () => { mirrorURL: tufRepo.baseURL, cachePath: tufRepo.cachePath, retry: false, - rootPath: 'n/a', + rootPath: path.join(tufRepo.cachePath, 'root.json'), }; }); @@ -96,13 +97,13 @@ describe('initTUF', () => { mirrorURL: tufRepo.baseURL, cachePath: tufRepo.cachePath, retry: false, - rootPath: 'n/a', + rootPath: path.join(tufRepo.cachePath, 'root.json'), }; }); afterEach(() => tufRepo?.teardown()); - it('returns a TUFCLient', async () => { + it('returns a TUFClient', async () => { const tuf = await initTUF(options); expect(tuf).toBeInstanceOf(TUFClient); }); @@ -110,13 +111,12 @@ describe('initTUF', () => { it('sets-up the local TUF cache', async () => { await initTUF(options); - const cachePath = tufRepo!.cachePath; + const cachePath = path.join( + tufRepo!.cachePath, + new URL(options!.mirrorURL!).host + ); expect(fs.existsSync(cachePath)).toBe(true); - expect(fs.existsSync(`${cachePath}/remote.json`)).toBe(true); expect(fs.existsSync(`${cachePath}/root.json`)).toBe(true); - expect(fs.existsSync(`${cachePath}/snapshot.json`)).toBe(true); - expect(fs.existsSync(`${cachePath}/timestamp.json`)).toBe(true); - expect(fs.existsSync(`${cachePath}/targets.json`)).toBe(true); expect(fs.existsSync(`${cachePath}/targets`)).toBe(true); }); }); diff --git a/packages/tuf/src/client.ts b/packages/tuf/src/client.ts index f8eda2392..10e3f5256 100644 --- a/packages/tuf/src/client.ts +++ b/packages/tuf/src/client.ts @@ -16,12 +16,16 @@ limitations under the License. import fs from 'fs'; import path from 'path'; import { Config, Updater } from 'tuf-js'; +import { TUFError } from '.'; +import { REPO_SEEDS } from './store'; import { readTarget } from './target'; import type { MakeFetchHappenOptions } from 'make-fetch-happen'; export type Retry = MakeFetchHappenOptions['retry']; +const TARGETS_DIR_NAME = 'targets'; + type FetchOptions = { retry?: Retry; timeout?: number; @@ -30,7 +34,7 @@ type FetchOptions = { export type TUFOptions = { cachePath: string; mirrorURL: string; - rootPath: string; + rootPath?: string; force: boolean; } & FetchOptions; @@ -38,17 +42,25 @@ export interface TUF { getTarget(targetName: string): Promise; } -interface RemoteConfig { - mirror: string; -} - export class TUFClient implements TUF { private updater: Updater; constructor(options: TUFOptions) { - initTufCache(options); - const remote = initRemoteConfig(options); - this.updater = initClient(options.cachePath, remote, options); + const url = new URL(options.mirrorURL); + const repoName = encodeURIComponent( + url.host + url.pathname.replace(/\/$/, '') + ); + const cachePath = path.join(options.cachePath, repoName); + + initTufCache(cachePath); + seedCache({ + cachePath, + mirrorURL: options.mirrorURL, + tufRootPath: options.rootPath, + force: options.force, + }); + + this.updater = initClient(options.mirrorURL, cachePath, options); } public async refresh(): Promise { @@ -65,13 +77,8 @@ export class TUFClient implements TUF { // created. If the targets directory does not exist, it will be created. // If the root.json file does not exist, it will be copied from the // rootPath argument. -function initTufCache({ - cachePath, - rootPath: tufRootPath, - force, -}: TUFOptions): string { - const targetsPath = path.join(cachePath, 'targets'); - const cachedRootPath = path.join(cachePath, 'root.json'); +function initTufCache(cachePath: string): void { + const targetsPath = path.join(cachePath, TARGETS_DIR_NAME); if (!fs.existsSync(cachePath)) { fs.mkdirSync(cachePath, { recursive: true }); @@ -80,60 +87,70 @@ function initTufCache({ if (!fs.existsSync(targetsPath)) { fs.mkdirSync(targetsPath); } - - // If the root.json file does not exist (or we're forcing re-initialization), - // copy it from the rootPath argument - if (!fs.existsSync(cachedRootPath) || force) { - fs.copyFileSync(tufRootPath, cachedRootPath); - } - - return cachePath; } -// Initializes the remote.json file, which contains the URL of the TUF -// repository. If the file does not exist, it will be created. If the file -// exists, it will be parsed and returned. -function initRemoteConfig({ +// Populates the TUF cache with the initial root.json file. If the root.json +// file does not exist (or we're forcing re-initialization), copy it from either +// the rootPath argument or from one of the repo seeds. +function seedCache({ cachePath, mirrorURL, + tufRootPath, force, -}: TUFOptions): RemoteConfig { - let remoteConfig: RemoteConfig | undefined; - const remoteConfigPath = path.join(cachePath, 'remote.json'); - - // If the remote config file exists, read it and parse it (skip if force is - // true) - if (!force && fs.existsSync(remoteConfigPath)) { - const data = fs.readFileSync(remoteConfigPath, 'utf-8'); - remoteConfig = JSON.parse(data); - } +}: { + cachePath: string; + mirrorURL: string; + tufRootPath?: string; + force: boolean; +}): void { + const cachedRootPath = path.join(cachePath, 'root.json'); - // If the remote config file does not exist (or we're forcing initialization), - // create it - if (!remoteConfig || force) { - remoteConfig = { mirror: mirrorURL }; - fs.writeFileSync(remoteConfigPath, JSON.stringify(remoteConfig)); + // If the root.json file does not exist (or we're forcing re-initialization), + // populate it either from the supplied rootPath or from one of the repo seeds. + if (!fs.existsSync(cachedRootPath) || force) { + if (tufRootPath) { + fs.copyFileSync(tufRootPath, cachedRootPath); + } else { + const repoSeed = REPO_SEEDS[mirrorURL]; + + if (!repoSeed) { + throw new TUFError({ + code: 'TUF_INIT_CACHE_ERROR', + message: `No root.json found for mirror: ${mirrorURL}`, + }); + } + + fs.writeFileSync( + cachedRootPath, + Buffer.from(repoSeed['root.json'], 'base64') + ); + + // Copy any seed targets into the cache + Object.entries(repoSeed.targets).forEach(([targetName, target]) => { + fs.writeFileSync( + path.join(cachePath, TARGETS_DIR_NAME, targetName), + Buffer.from(target, 'base64') + ); + }); + } } - - return remoteConfig; } function initClient( + mirrorURL: string, cachePath: string, - remote: RemoteConfig, options: FetchOptions ): Updater { - const baseURL = remote.mirror; const config: Partial = { fetchTimeout: options.timeout, fetchRetry: options.retry, }; return new Updater({ - metadataBaseUrl: baseURL, - targetBaseUrl: `${baseURL}/targets`, + metadataBaseUrl: mirrorURL, + targetBaseUrl: `${mirrorURL}/targets`, metadataDir: cachePath, - targetDir: path.join(cachePath, 'targets'), + targetDir: path.join(cachePath, TARGETS_DIR_NAME), config, }); } diff --git a/packages/tuf/src/error.ts b/packages/tuf/src/error.ts index 58465fcf2..2ca12c721 100644 --- a/packages/tuf/src/error.ts +++ b/packages/tuf/src/error.ts @@ -15,6 +15,7 @@ limitations under the License. */ /* eslint-disable @typescript-eslint/no-explicit-any */ type TUFErrorCode = + | 'TUF_INIT_CACHE_ERROR' | 'TUF_FIND_TARGET_ERROR' | 'TUF_REFRESH_METADATA_ERROR' | 'TUF_DOWNLOAD_TARGET_ERROR' diff --git a/packages/tuf/src/index.ts b/packages/tuf/src/index.ts index d0d7ee8f9..423843636 100644 --- a/packages/tuf/src/index.ts +++ b/packages/tuf/src/index.ts @@ -24,7 +24,6 @@ import { export const DEFAULT_MIRROR_URL = 'https://tuf-repo-cdn.sigstore.dev'; const DEFAULT_CACHE_DIR = 'sigstore-js'; -const DEFAULT_TUF_ROOT_PATH = '../store/public-good-instance-root.json'; const DEFAULT_RETRY: Retry = { retries: 2 }; const DEFAULT_TIMEOUT = 5000; @@ -54,7 +53,7 @@ function createClient(options: TUFOptions) { /* istanbul ignore next */ return new TUFClient({ cachePath: options.cachePath || appDataPath(DEFAULT_CACHE_DIR), - rootPath: options.rootPath || require.resolve(DEFAULT_TUF_ROOT_PATH), + rootPath: options.rootPath, mirrorURL: options.mirrorURL || DEFAULT_MIRROR_URL, retry: options.retry ?? DEFAULT_RETRY, timeout: options.timeout ?? DEFAULT_TIMEOUT, diff --git a/packages/tuf/src/store.ts b/packages/tuf/src/store.ts new file mode 100644 index 000000000..a66d41e4e --- /dev/null +++ b/packages/tuf/src/store.ts @@ -0,0 +1,17 @@ +type RepoSeed = { + 'root.json': string; + targets: Record; +}; + +export const REPO_SEEDS: Record = { + 'https://tuf-repo-cdn.sigstore.dev': { + 'root.json': + 'eyJzaWduZWQiOnsiX3R5cGUiOiJyb290Iiwic3BlY192ZXJzaW9uIjoiMS4wIiwidmVyc2lvbiI6NywiZXhwaXJlcyI6IjIwMjMtMTAtMDRUMTM6MDg6MTFaIiwia2V5cyI6eyIyNWEwZWI0NTBmZDNlZTJiZDc5MjE4Yzk2M2RjZTNmMWNjNjExOGJhZGYyNTFiZjE0OWYwYmQwN2Q1Y2FiZTk5Ijp7ImtleXR5cGUiOiJlY2RzYS1zaGEyLW5pc3RwMjU2Iiwic2NoZW1lIjoiZWNkc2Etc2hhMi1uaXN0cDI1NiIsImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6WyJzaGEyNTYiLCJzaGE1MTIiXSwia2V5dmFsIjp7InB1YmxpYyI6Ii0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVFWHN6M1NaWEZiOGpNVjQyajZwSmx5amJqUjhLXG5OM0J3b2NleHE2TE1JYjVxc1dLT1F2TE4xNk5VZWZMYzRIc3dPb3VtUnNWVmFhalNwUVM2Zm9ia1J3PT1cbi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLVxuIn19LCIyZTYxY2QwY2JmNGE4ZjQ1ODA5YmRhOWY3Zjc4YzBkMzNhZDExODQyZmY5NGFlMzQwODczZTI2NjRkYzg0M2RlIjp7ImtleXR5cGUiOiJlY2RzYS1zaGEyLW5pc3RwMjU2Iiwic2NoZW1lIjoiZWNkc2Etc2hhMi1uaXN0cDI1NiIsImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6WyJzaGEyNTYiLCJzaGE1MTIiXSwia2V5dmFsIjp7InB1YmxpYyI6Ii0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUUwZ2hyaDkyTHcxWXIzaWRHVjVXcUN0TURCOEN4XG4rRDhoZEM0dzJaTE5JcGxWUm9WR0xza1lhM2doZU15T2ppSjhrUGkxNWFRMi8vN1Arb2o3VXZKUEd3PT1cbi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLVxuIn19LCI0NWIyODM4MjVlYjE4NGNhYmQ1ODJlYjE3Yjc0ZmM4ZWQ0MDRmNjhjZjQ1MmFjYWJkYWQyZWQ2ZjkwY2UyMTZiIjp7ImtleXR5cGUiOiJlY2RzYS1zaGEyLW5pc3RwMjU2Iiwic2NoZW1lIjoiZWNkc2Etc2hhMi1uaXN0cDI1NiIsImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6WyJzaGEyNTYiLCJzaGE1MTIiXSwia2V5dmFsIjp7InB1YmxpYyI6Ii0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVMcld2TnQ5NHY0UjA4NUVMZWVDTXhIcDdQbGRGXG4wL1QxR3h1a1VoMk9EdWdnTEdKRTBwYzFlOENTQmY2Q1M5MUZ3bzlGVU91UnNqQlVsZCtWcVN5Q2RRPT1cbi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLVxuIn19LCI3Zjc1MTNiMjU0MjlhNjQ0NzNlMTBjZTNhZDJmM2RhMzcyYmJkZDE0YjY1ZDA3YmJhZjU0N2U3YzhiYmJlNjJiIjp7ImtleXR5cGUiOiJlY2RzYS1zaGEyLW5pc3RwMjU2Iiwic2NoZW1lIjoiZWNkc2Etc2hhMi1uaXN0cDI1NiIsImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6WyJzaGEyNTYiLCJzaGE1MTIiXSwia2V5dmFsIjp7InB1YmxpYyI6Ii0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVpbmlrU3NBUW1Za05lSDVlWXEvQ25JekxhYWNPXG54bFNhYXdRRE93cUt5L3RDcXhxNXh4UFNKYzIxSzRXSWhzOUd5T2tLZnp1ZVkzR0lMemNNSlo0Y1d3PT1cbi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLVxuIn19LCJlMTg2M2JhMDIwNzAzMjJlYmM2MjZkY2VjZjlkODgxYTNhMzhjMzVjM2I0MWE4Mzc2NWI2YWQ2YzM3ZWFlYzJhIjp7ImtleXR5cGUiOiJlY2RzYS1zaGEyLW5pc3RwMjU2Iiwic2NoZW1lIjoiZWNkc2Etc2hhMi1uaXN0cDI1NiIsImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6WyJzaGEyNTYiLCJzaGE1MTIiXSwia2V5dmFsIjp7InB1YmxpYyI6Ii0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVXUmlHcjUraiszSjVTc0grWnRyNW5FMkgyd083XG5CVituTzNzOTNnTGNhMThxVE96SFkxb1d5QUdEeWtNU3NHVFVCU3Q5RCtBbjBLZktzRDJtZlNNNDJRPT1cbi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLVxuIn19LCJmNTMxMmY1NDJjMjEyNzNkOTQ4NWE0OTM5NDM4NmM0NTc1ODA0NzcwNjY3ZjJkZGI1OWIzYmYwNjY5ZmRkZDJmIjp7ImtleXR5cGUiOiJlY2RzYS1zaGEyLW5pc3RwMjU2Iiwic2NoZW1lIjoiZWNkc2Etc2hhMi1uaXN0cDI1NiIsImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6WyJzaGEyNTYiLCJzaGE1MTIiXSwia2V5dmFsIjp7InB1YmxpYyI6Ii0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUV6QnpWT21IQ1Bvak1WTFNJMzY0V2lpVjhOUHJEXG42SWdSeFZsaXNrei92K3kzSkVSNW1jVkdjT05saURjV01DNUoybGZIbWpQTlBoYjRIN3htOEx6ZlNBPT1cbi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLVxuIn19LCJmZjUxZTE3ZmNmMjUzMTE5YjcwMzNmNmY1NzUxMjYzMWRhNGEwOTY5NDQyYWZjZjlmYzhiMTQxYzdmMmJlOTljIjp7ImtleXR5cGUiOiJlY2RzYS1zaGEyLW5pc3RwMjU2Iiwic2NoZW1lIjoiZWNkc2Etc2hhMi1uaXN0cDI1NiIsImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6WyJzaGEyNTYiLCJzaGE1MTIiXSwia2V5dmFsIjp7InB1YmxpYyI6Ii0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUV5OFhLc21oQllESThKYzBHd3pCeGVLYXgwY201XG5TVEtFVTY1SFBGdW5VbjQxc1Q4cGkwRmpNNElrSHovWVVtd21MVU8wV3Q3bHhoajZCa0xJSzRxWUF3PT1cbi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLVxuIn19fSwicm9sZXMiOnsicm9vdCI6eyJrZXlpZHMiOlsiZmY1MWUxN2ZjZjI1MzExOWI3MDMzZjZmNTc1MTI2MzFkYTRhMDk2OTQ0MmFmY2Y5ZmM4YjE0MWM3ZjJiZTk5YyIsIjI1YTBlYjQ1MGZkM2VlMmJkNzkyMThjOTYzZGNlM2YxY2M2MTE4YmFkZjI1MWJmMTQ5ZjBiZDA3ZDVjYWJlOTkiLCJmNTMxMmY1NDJjMjEyNzNkOTQ4NWE0OTM5NDM4NmM0NTc1ODA0NzcwNjY3ZjJkZGI1OWIzYmYwNjY5ZmRkZDJmIiwiN2Y3NTEzYjI1NDI5YTY0NDczZTEwY2UzYWQyZjNkYTM3MmJiZGQxNGI2NWQwN2JiYWY1NDdlN2M4YmJiZTYyYiIsIjJlNjFjZDBjYmY0YThmNDU4MDliZGE5ZjdmNzhjMGQzM2FkMTE4NDJmZjk0YWUzNDA4NzNlMjY2NGRjODQzZGUiXSwidGhyZXNob2xkIjozfSwic25hcHNob3QiOnsia2V5aWRzIjpbIjQ1YjI4MzgyNWViMTg0Y2FiZDU4MmViMTdiNzRmYzhlZDQwNGY2OGNmNDUyYWNhYmRhZDJlZDZmOTBjZTIxNmIiXSwidGhyZXNob2xkIjoxfSwidGFyZ2V0cyI6eyJrZXlpZHMiOlsiZmY1MWUxN2ZjZjI1MzExOWI3MDMzZjZmNTc1MTI2MzFkYTRhMDk2OTQ0MmFmY2Y5ZmM4YjE0MWM3ZjJiZTk5YyIsIjI1YTBlYjQ1MGZkM2VlMmJkNzkyMThjOTYzZGNlM2YxY2M2MTE4YmFkZjI1MWJmMTQ5ZjBiZDA3ZDVjYWJlOTkiLCJmNTMxMmY1NDJjMjEyNzNkOTQ4NWE0OTM5NDM4NmM0NTc1ODA0NzcwNjY3ZjJkZGI1OWIzYmYwNjY5ZmRkZDJmIiwiN2Y3NTEzYjI1NDI5YTY0NDczZTEwY2UzYWQyZjNkYTM3MmJiZGQxNGI2NWQwN2JiYWY1NDdlN2M4YmJiZTYyYiIsIjJlNjFjZDBjYmY0YThmNDU4MDliZGE5ZjdmNzhjMGQzM2FkMTE4NDJmZjk0YWUzNDA4NzNlMjY2NGRjODQzZGUiXSwidGhyZXNob2xkIjozfSwidGltZXN0YW1wIjp7ImtleWlkcyI6WyJlMTg2M2JhMDIwNzAzMjJlYmM2MjZkY2VjZjlkODgxYTNhMzhjMzVjM2I0MWE4Mzc2NWI2YWQ2YzM3ZWFlYzJhIl0sInRocmVzaG9sZCI6MX19LCJjb25zaXN0ZW50X3NuYXBzaG90Ijp0cnVlfSwic2lnbmF0dXJlcyI6W3sia2V5aWQiOiIyNWEwZWI0NTBmZDNlZTJiZDc5MjE4Yzk2M2RjZTNmMWNjNjExOGJhZGYyNTFiZjE0OWYwYmQwN2Q1Y2FiZTk5Iiwic2lnIjoiMzA0NjAyMjEwMGMwNjEwYzAwNTVjZTVjNGE1MmQwNTRkNzMyMmU3YjUxNGQ1NWJhZjQ0NDIzZDYzYWE0ZGFhMDc3Y2M2MGZkMWYwMjIxMDBhMDk3ZjI4MDNmMDkwZmI2NmM0MmVhZDkxNWEyYzQ2ZWJlN2RiNTNhMzJiZjE4ZjIxODgyNzVjYzkzNmY4YmRkIn0seyJrZXlpZCI6ImY1MzEyZjU0MmMyMTI3M2Q5NDg1YTQ5Mzk0Mzg2YzQ1NzU4MDQ3NzA2NjdmMmRkYjU5YjNiZjA2NjlmZGRkMmYiLCJzaWciOiIzMDQ1MDIyMDMxMzRmMDQ2ODgxMDI5OWQ1NDkzYTg2N2M0MDYzMGIzNDEyOTZiOTJlNTljMjk4MjEzMTFkMzUzMzQzYmIzYTQwMjIxMDBlNjY3YWUzZDMwNGU3ZTNkYTA4OTRjNzQyNWY2YjllY2Q5MTcxMDY4NDEyODBlNWNmNmYzNDk2YWQ1ZjhmNjhlIn0seyJrZXlpZCI6IjdmNzUxM2IyNTQyOWE2NDQ3M2UxMGNlM2FkMmYzZGEzNzJiYmRkMTRiNjVkMDdiYmFmNTQ3ZTdjOGJiYmU2MmIiLCJzaWciOiIzMDQ1MDIyMDM3ZmU1ZjQ1NDI2ZjIxZWFhZjQ3MzBkMjEzNmYyYjE2MTFkNjM3OTY4OGY3OWI5ZDFlM2Y2MTcxOTk5NzEzNWMwMjIxMDBiNjNiMDIyZDdiNzlkNDY5NGI5NmY0MTZkODhhYTRkN2IxYTNiZmY4YTAxZjRmYjUxZTBmNDIxMzdjN2QyZDA2In0seyJrZXlpZCI6IjJlNjFjZDBjYmY0YThmNDU4MDliZGE5ZjdmNzhjMGQzM2FkMTE4NDJmZjk0YWUzNDA4NzNlMjY2NGRjODQzZGUiLCJzaWciOiIzMDQ0MDIyMDA3Y2M4ZmNjNDk0MDgwOWYyNzUxYWQ1YjUzNWY0YzVmNTNmNWI0OTUyZjViNTY5NmIwOTY2OGU3NDMzMDZhYzEwMjIwMDZkZmNkZjk0ZTk0YzkyMTYzZWViMWI0Nzc5NmRiNjJjZWRhYTczMGFhMTNhYTYxYjU3M2ZlMjM3MTQ3MzBmMiJ9XX0K', + targets: { + 'trusted_root.json': + 'ewogICJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLmRldi5zaWdzdG9yZS50cnVzdGVkcm9vdCtqc29uO3ZlcnNpb249MC4xIiwKICAidGxvZ3MiOiBbCiAgICB7CiAgICAgICJiYXNlVXJsIjogImh0dHBzOi8vcmVrb3Iuc2lnc3RvcmUuZGV2IiwKICAgICAgImhhc2hBbGdvcml0aG0iOiAiU0hBMl8yNTYiLAogICAgICAicHVibGljS2V5IjogewogICAgICAgICJyYXdCeXRlcyI6ICJNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUUyRzJZKzJ0YWJkVFY1QmNHaUJJeDBhOWZBRndya0JibUxTR3RrczRMM3FYNnlZWTB6dWZCbmhDOFVyL2l5NTVHaFdQLzlBL2JZMkxoQzMwTTkrUll0dz09IiwKICAgICAgICAia2V5RGV0YWlscyI6ICJQS0lYX0VDRFNBX1AyNTZfU0hBXzI1NiIsCiAgICAgICAgInZhbGlkRm9yIjogewogICAgICAgICAgInN0YXJ0IjogIjIwMjEtMDEtMTJUMTE6NTM6MjcuMDAwWiIKICAgICAgICB9CiAgICAgIH0sCiAgICAgICJsb2dJZCI6IHsKICAgICAgICAia2V5SWQiOiAid05JOWF0UUdseitWV2ZPNkxSeWdINFFVZlkvOFc0UkZ3aVQ1aTVXUmdCMD0iCiAgICAgIH0KICAgIH0KICBdLAogICJjZXJ0aWZpY2F0ZUF1dGhvcml0aWVzIjogWwogICAgewogICAgICAic3ViamVjdCI6IHsKICAgICAgICAib3JnYW5pemF0aW9uIjogInNpZ3N0b3JlLmRldiIsCiAgICAgICAgImNvbW1vbk5hbWUiOiAic2lnc3RvcmUiCiAgICAgIH0sCiAgICAgICJ1cmkiOiAiaHR0cHM6Ly9mdWxjaW8uc2lnc3RvcmUuZGV2IiwKICAgICAgImNlcnRDaGFpbiI6IHsKICAgICAgICAiY2VydGlmaWNhdGVzIjogWwogICAgICAgICAgewogICAgICAgICAgICAicmF3Qnl0ZXMiOiAiTUlJQitEQ0NBWDZnQXdJQkFnSVROVmtEWm9DaW9mUERzeTdkZm02Z2VMYnVoekFLQmdncWhrak9QUVFEQXpBcU1SVXdFd1lEVlFRS0V3eHphV2R6ZEc5eVpTNWtaWFl4RVRBUEJnTlZCQU1UQ0hOcFozTjBiM0psTUI0WERUSXhNRE13TnpBek1qQXlPVm9YRFRNeE1ESXlNekF6TWpBeU9Wb3dLakVWTUJNR0ExVUVDaE1NYzJsbmMzUnZjbVV1WkdWMk1SRXdEd1lEVlFRREV3aHphV2R6ZEc5eVpUQjJNQkFHQnlxR1NNNDlBZ0VHQlN1QkJBQWlBMklBQkxTeUE3SWk1aytwTk84WkVXWTB5bGVtV0Rvd09rTmEza0wrR1pFNVo1R1dlaEw5L0E5YlJOQTNSYnJzWjVpMEpjYXN0YVJMN1NwNWZwL2pENWR4cWMvVWRUVm5sdlMxNmFuKzJZZnN3ZS9RdUxvbFJVQ3JjT0UyKzJpQTUrdHpkNk5tTUdRd0RnWURWUjBQQVFIL0JBUURBZ0VHTUJJR0ExVWRFd0VCL3dRSU1BWUJBZjhDQVFFd0hRWURWUjBPQkJZRUZNakZIUUJCbWlRcE1sRWs2dzJ1U3UxS0J0UHNNQjhHQTFVZEl3UVlNQmFBRk1qRkhRQkJtaVFwTWxFazZ3MnVTdTFLQnRQc01Bb0dDQ3FHU000OUJBTURBMmdBTUdVQ01IOGxpV0pmTXVpNnZYWEJoakRnWTRNd3NsbU4vVEp4VmUvODNXckZvbXdtTmYwNTZ5MVg0OEY5YzRtM2Ezb3pYQUl4QUtqUmF5NS9hai9qc0tLR0lrbVFhdGpJOHV1cEhyLytDeEZ2YUpXbXBZcU5rTERHUlUrOW9yemg1aEkyUnJjdWFRPT0iCiAgICAgICAgICB9CiAgICAgICAgXQogICAgICB9LAogICAgICAidmFsaWRGb3IiOiB7CiAgICAgICAgInN0YXJ0IjogIjIwMjEtMDMtMDdUMDM6MjA6MjkuMDAwWiIsCiAgICAgICAgImVuZCI6ICIyMDIyLTEyLTMxVDIzOjU5OjU5Ljk5OVoiCiAgICAgIH0KICAgIH0sCiAgICB7CiAgICAgICJzdWJqZWN0IjogewogICAgICAgICJvcmdhbml6YXRpb24iOiAic2lnc3RvcmUuZGV2IiwKICAgICAgICAiY29tbW9uTmFtZSI6ICJzaWdzdG9yZSIKICAgICAgfSwKICAgICAgInVyaSI6ICJodHRwczovL2Z1bGNpby5zaWdzdG9yZS5kZXYiLAogICAgICAiY2VydENoYWluIjogewogICAgICAgICJjZXJ0aWZpY2F0ZXMiOiBbCiAgICAgICAgICB7CiAgICAgICAgICAgICJyYXdCeXRlcyI6ICJNSUlDR2pDQ0FhR2dBd0lCQWdJVUFMblZpVmZuVTBickphc21Sa0hybi9VbmZhUXdDZ1lJS29aSXpqMEVBd013S2pFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUkV3RHdZRFZRUURFd2h6YVdkemRHOXlaVEFlRncweU1qQTBNVE15TURBMk1UVmFGdzB6TVRFd01EVXhNelUyTlRoYU1EY3hGVEFUQmdOVkJBb1RESE5wWjNOMGIzSmxMbVJsZGpFZU1Cd0dBMVVFQXhNVmMybG5jM1J2Y21VdGFXNTBaWEp0WldScFlYUmxNSFl3RUFZSEtvWkl6ajBDQVFZRks0RUVBQ0lEWWdBRThSVlMveXNIK05PdnVEWnlQSVp0aWxnVUY5TmxhcllwQWQ5SFAxdkJCSDFVNUNWNzdMU1M3czBaaUg0bkU3SHY3cHRTNkx2dlIvU1RrNzk4TFZnTXpMbEo0SGVJZkYzdEhTYWV4TGNZcFNBU3Ixa1MwTi9SZ0JKei85aldDaVhubzNzd2VUQU9CZ05WSFE4QkFmOEVCQU1DQVFZd0V3WURWUjBsQkF3d0NnWUlLd1lCQlFVSEF3TXdFZ1lEVlIwVEFRSC9CQWd3QmdFQi93SUJBREFkQmdOVkhRNEVGZ1FVMzlQcHoxWWtFWmI1cU5qcEtGV2l4aTRZWkQ4d0h3WURWUjBqQkJnd0ZvQVVXTUFlWDVGRnBXYXBlc3lRb1pNaTBDckZ4Zm93Q2dZSUtvWkl6ajBFQXdNRFp3QXdaQUl3UENzUUs0RFlpWllEUElhRGk1SEZLbmZ4WHg2QVNTVm1FUmZzeW5ZQmlYMlg2U0pSblpVODQvOURaZG5GdnZ4bUFqQk90NlFwQmxjNEovMER4dmtUQ3FwY2x2emlMNkJDQ1BuamRsSUIzUHUzQnhzUG15Z1VZN0lpMnpiZENkbGlpb3c9IgogICAgICAgICAgfSwKICAgICAgICAgIHsKICAgICAgICAgICAgInJhd0J5dGVzIjogIk1JSUI5ekNDQVh5Z0F3SUJBZ0lVQUxaTkFQRmR4SFB3amVEbG9Ed3lZQ2hBTy80d0NnWUlLb1pJemowRUF3TXdLakVWTUJNR0ExVUVDaE1NYzJsbmMzUnZjbVV1WkdWMk1SRXdEd1lEVlFRREV3aHphV2R6ZEc5eVpUQWVGdzB5TVRFd01EY3hNelUyTlRsYUZ3MHpNVEV3TURVeE16VTJOVGhhTUNveEZUQVRCZ05WQkFvVERITnBaM04wYjNKbExtUmxkakVSTUE4R0ExVUVBeE1JYzJsbmMzUnZjbVV3ZGpBUUJnY3Foa2pPUFFJQkJnVXJnUVFBSWdOaUFBVDdYZUZUNHJiM1BRR3dTNElhanRMazMvT2xucGdhbmdhQmNsWXBzWUJyNWkrNHluQjA3Y2ViM0xQME9JT1pkeGV4WDY5YzVpVnV5SlJRK0h6MDV5aStVRjN1QldBbEhwaVM1c2gwK0gyR0hFN1NYcmsxRUM1bTFUcjE5TDlnZzkyall6QmhNQTRHQTFVZER3RUIvd1FFQXdJQkJqQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01CMEdBMVVkRGdRV0JCUll3QjVma1VXbFpxbDZ6SkNoa3lMUUtzWEYrakFmQmdOVkhTTUVHREFXZ0JSWXdCNWZrVVdsWnFsNnpKQ2hreUxRS3NYRitqQUtCZ2dxaGtqT1BRUURBd05wQURCbUFqRUFqMW5IZVhacCsxM05XQk5hK0VEc0RQOEcxV1dnMXRDTVdQL1dIUHFwYVZvMGpoc3dlTkZaZ1NzMGVFN3dZSTRxQWpFQTJXQjlvdDk4c0lrb0YzdlpZZGQzL1Z0V0I1YjlUTk1lYTdJeC9zdEo1VGZjTExlQUJMRTRCTkpPc1E0dm5CSEoiCiAgICAgICAgICB9CiAgICAgICAgXQogICAgICB9LAogICAgICAidmFsaWRGb3IiOiB7CiAgICAgICAgInN0YXJ0IjogIjIwMjItMDQtMTNUMjA6MDY6MTUuMDAwWiIKICAgICAgfQogICAgfQogIF0sCiAgImN0bG9ncyI6IFsKICAgIHsKICAgICAgImJhc2VVcmwiOiAiaHR0cHM6Ly9jdGZlLnNpZ3N0b3JlLmRldi90ZXN0IiwKICAgICAgImhhc2hBbGdvcml0aG0iOiAiU0hBMl8yNTYiLAogICAgICAicHVibGljS2V5IjogewogICAgICAgICJyYXdCeXRlcyI6ICJNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUViZndSK1JKdWRYc2NnUkJScEtYMVhGRHkzUHl1ZER4ei9TZm5SaTFmVDhla3BmQmQyTzF1b3o3anIzWjhuS3p4QTY5RVVRK2VGQ0ZJM3pldWJQV1U3dz09IiwKICAgICAgICAia2V5RGV0YWlscyI6ICJQS0lYX0VDRFNBX1AyNTZfU0hBXzI1NiIsCiAgICAgICAgInZhbGlkRm9yIjogewogICAgICAgICAgInN0YXJ0IjogIjIwMjEtMDMtMTRUMDA6MDA6MDAuMDAwWiIsCiAgICAgICAgICAiZW5kIjogIjIwMjItMTAtMzFUMjM6NTk6NTkuOTk5WiIKICAgICAgICB9CiAgICAgIH0sCiAgICAgICJsb2dJZCI6IHsKICAgICAgICAia2V5SWQiOiAiQ0dDUzhDaFMvMmhGMGRGcko0U2NSV2NZckJZOXd6alNiZWE4SWdZMmIzST0iCiAgICAgIH0KICAgIH0sCiAgICB7CiAgICAgICJiYXNlVXJsIjogImh0dHBzOi8vY3RmZS5zaWdzdG9yZS5kZXYvMjAyMiIsCiAgICAgICJoYXNoQWxnb3JpdGhtIjogIlNIQTJfMjU2IiwKICAgICAgInB1YmxpY0tleSI6IHsKICAgICAgICAicmF3Qnl0ZXMiOiAiTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFaVBTbEZpMENtRlRmRWpDVXFGOUh1Q0VjWVhOS0FhWWFsSUptQlo4eXllelBqVHFoeHJLQnBNbmFvY1Z0TEpCSTFlTTN1WG5RelFHQUpkSjRnczlGeXc9PSIsCiAgICAgICAgImtleURldGFpbHMiOiAiUEtJWF9FQ0RTQV9QMjU2X1NIQV8yNTYiLAogICAgICAgICJ2YWxpZEZvciI6IHsKICAgICAgICAgICJzdGFydCI6ICIyMDIyLTEwLTIwVDAwOjAwOjAwLjAwMFoiCiAgICAgICAgfQogICAgICB9LAogICAgICAibG9nSWQiOiB7CiAgICAgICAgImtleUlkIjogIjNUMHdhc2JIRVRKakdSNGNtV2MzQXFKS1hyamVQSzMvaDRweWdDOHA3bzQ9IgogICAgICB9CiAgICB9CiAgXSwKICAidGltZXN0YW1wQXV0aG9yaXRpZXMiOiBbCiAgICB7CiAgICAgICJzdWJqZWN0IjogewogICAgICAgICJvcmdhbml6YXRpb24iOiAiR2l0SHViLCBJbmMuIiwKICAgICAgICAiY29tbW9uTmFtZSI6ICJJbnRlcm5hbCBTZXJ2aWNlcyBSb290IgogICAgICB9LAogICAgICAiY2VydENoYWluIjogewogICAgICAgICJjZXJ0aWZpY2F0ZXMiOiBbCiAgICAgICAgICB7CiAgICAgICAgICAgICJyYXdCeXRlcyI6ICJNSUlCM0RDQ0FXS2dBd0lCQWdJVWNoa05zSDM2WGEwNGIxTHFJYytxcjlEVmVjTXdDZ1lJS29aSXpqMEVBd013TWpFVk1CTUdBMVVFQ2hNTVIybDBTSFZpTENCSmJtTXVNUmt3RndZRFZRUURFeEJVVTBFZ2FXNTBaWEp0WldScFlYUmxNQjRYRFRJek1EUXhOREF3TURBd01Gb1hEVEkwTURReE16QXdNREF3TUZvd01qRVZNQk1HQTFVRUNoTU1SMmwwU0hWaUxDQkpibU11TVJrd0Z3WURWUVFERXhCVVUwRWdWR2x0WlhOMFlXMXdhVzVuTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFVUQ1Wk5iU3FZTWQ2cjhxcE9PRVg5aWJHblpUOUdzdVhPaHIvZjhVOUZKdWdCR0V4S1lwNDBPVUxTMGVyalpXN3hWOXhWNTJObkpmNU9lRHE0ZTVaS3FOV01GUXdEZ1lEVlIwUEFRSC9CQVFEQWdlQU1CTUdBMVVkSlFRTU1Bb0dDQ3NHQVFVRkJ3TUlNQXdHQTFVZEV3RUIvd1FDTUFBd0h3WURWUjBqQkJnd0ZvQVVhVzFSdWRPZ1Z0MGxlcVkwV0tZYnVQcjQ3d0F3Q2dZSUtvWkl6ajBFQXdNRGFBQXdaUUl3YlVIOUh2RDRlakNaSk9XUW5xQWxrcVVSbGx2dTlNOCtWcUxiaVJLK3pTZlpDWndzaWxqUm44TVFRUlNrWEVFNUFqRUFnK1Z4cXRvamZWZnU4RGh6emhDeDlHS0VUYkpIYjE5aVY3Mm1NS1ViREFGbXpaNmJROGI1NFpiOHRpZHk1YVdlIgogICAgICAgICAgfSwKICAgICAgICAgIHsKICAgICAgICAgICAgInJhd0J5dGVzIjogIk1JSUNFRENDQVpXZ0F3SUJBZ0lVWDhaTzVRWFA3dk40ZE1RNWU5c1UzbnViOE9nd0NnWUlLb1pJemowRUF3TXdPREVWTUJNR0ExVUVDaE1NUjJsMFNIVmlMQ0JKYm1NdU1SOHdIUVlEVlFRREV4WkpiblJsY201aGJDQlRaWEoyYVdObGN5QlNiMjkwTUI0WERUSXpNRFF4TkRBd01EQXdNRm9YRFRJNE1EUXhNakF3TURBd01Gb3dNakVWTUJNR0ExVUVDaE1NUjJsMFNIVmlMQ0JKYm1NdU1Sa3dGd1lEVlFRREV4QlVVMEVnYVc1MFpYSnRaV1JwWVhSbE1IWXdFQVlIS29aSXpqMENBUVlGSzRFRUFDSURZZ0FFdk1MWS9kVFZidklKWUFOQXVzekV3Sm5RRTFsbGZ0eW55TUtJTWhoNDhIbXFiVnI1eWd5YnpzTFJMVktiQldPZFoyMWFlSnorZ1ppeXRaZXRxY3lGOVdsRVI1TkVNZjZKVjdaTm9qUXB4SHE0UkhHb0dTY2VRdi9xdlRpWnhFREtvMll3WkRBT0JnTlZIUThCQWY4RUJBTUNBUVl3RWdZRFZSMFRBUUgvQkFnd0JnRUIvd0lCQURBZEJnTlZIUTRFRmdRVWFXMVJ1ZE9nVnQwbGVxWTBXS1lidVByNDd3QXdId1lEVlIwakJCZ3dGb0FVOU5ZWWxvYm5BRzRjMC9xanh5SC9scS93eitRd0NnWUlLb1pJemowRUF3TURhUUF3WmdJeEFLMUIxODV5Z0NySVlGbElzM0dqc3dqbndTTUc2TFk4d29MVmRha0tEWnhWYThmOGNxTXMxRGhjeEowKzA5dzk1UUl4QU8rdEJ6Wms3dmpVSjlpSmdENFI2WldUeFFXS3FObTc0ak85OW8rbzlzdjRGSS9TWlRaVEZ5TW4wSUpFSGRObXlBPT0iCiAgICAgICAgICB9LAogICAgICAgICAgewogICAgICAgICAgICAicmF3Qnl0ZXMiOiAiTUlJQjlEQ0NBWHFnQXdJQkFnSVVhL0pBa2RVaks0SlV3c3F0YWlSSkdXaHFMU293Q2dZSUtvWkl6ajBFQXdNd09ERVZNQk1HQTFVRUNoTU1SMmwwU0hWaUxDQkpibU11TVI4d0hRWURWUVFERXhaSmJuUmxjbTVoYkNCVFpYSjJhV05sY3lCU2IyOTBNQjRYRFRJek1EUXhOREF3TURBd01Gb1hEVE16TURReE1UQXdNREF3TUZvd09ERVZNQk1HQTFVRUNoTU1SMmwwU0hWaUxDQkpibU11TVI4d0hRWURWUVFERXhaSmJuUmxjbTVoYkNCVFpYSjJhV05sY3lCU2IyOTBNSFl3RUFZSEtvWkl6ajBDQVFZRks0RUVBQ0lEWWdBRWY5akZBWHh6NGt4NjhBSFJNT2tGQmhmbERjTVR2emFYejR4L0ZDY1hqSi8xcUVLb24vcVBJR25hVVJza0R0eU5iTkRPcGVKVERERnF0NDhpTVBybnpweDZJWndxZW1mVUpONHhCRVpmemErcFl0L2l5b2QrOXRacjIwUlJXU3YvbzBVd1F6QU9CZ05WSFE4QkFmOEVCQU1DQVFZd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFqQWRCZ05WSFE0RUZnUVU5TllZbG9ibkFHNGMwL3FqeHlIL2xxL3d6K1F3Q2dZSUtvWkl6ajBFQXdNRGFBQXdaUUl4QUxaTFo4QmdSWHpLeExNTU45VklsTytlNGhyQm5OQmdGN3R6N0hucm93djJOZXRaRXJJQUNLRnltQmx2V0R2dE1BSXdaTytraTZzc1ExYnNabzk4TzhtRUFmMk5aN2lpQ2dERFUwVndqZWNvNnp5ZWgwekJUczkvN2dWNkFITlE1M3hEIgogICAgICAgICAgfQogICAgICAgIF0KICAgICAgfSwKICAgICAgInZhbGlkRm9yIjogewogICAgICAgICJzdGFydCI6ICIyMDIzLTA0LTE0VDAwOjAwOjAwLjAwMFoiCiAgICAgIH0KICAgIH0KICBdCn0K', + 'registry.npmjs.org%2Fkeys.json': + 'ewogICAgImtleXMiOiBbCiAgICAgICAgewogICAgICAgICAgICAia2V5SWQiOiAiU0hBMjU2OmpsM2J3c3d1ODBQampva0NnaDBvMnc1YzJVNExoUUFFNTdnajljejFrekEiLAogICAgICAgICAgICAia2V5VXNhZ2UiOiAibnBtOnNpZ25hdHVyZXMiLAogICAgICAgICAgICAicHVibGljS2V5IjogewogICAgICAgICAgICAgICAgInJhd0J5dGVzIjogIk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTFPbGIzek1BRkZ4WEtIaUlrUU81Y0ozWWhsNWk2VVBwK0lodXRlQkpidUhjQTVVb2dLbzBFV3RsV3dXNktTYUtvVE5FWUw3SmxDUWlWbmtoQmt0VWdnPT0iLAogICAgICAgICAgICAgICAgImtleURldGFpbHMiOiAiUEtJWF9FQ0RTQV9QMjU2X1NIQV8yNTYiLAogICAgICAgICAgICAgICAgInZhbGlkRm9yIjogewogICAgICAgICAgICAgICAgICAgICJzdGFydCI6ICIxOTk5LTAxLTAxVDAwOjAwOjAwLjAwMFoiCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICAgImtleUlkIjogIlNIQTI1NjpqbDNid3N3dTgwUGpqb2tDZ2gwbzJ3NWMyVTRMaFFBRTU3Z2o5Y3oxa3pBIiwKICAgICAgICAgICAgImtleVVzYWdlIjogIm5wbTphdHRlc3RhdGlvbnMiLAogICAgICAgICAgICAicHVibGljS2V5IjogewogICAgICAgICAgICAgICAgInJhd0J5dGVzIjogIk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTFPbGIzek1BRkZ4WEtIaUlrUU81Y0ozWWhsNWk2VVBwK0lodXRlQkpidUhjQTVVb2dLbzBFV3RsV3dXNktTYUtvVE5FWUw3SmxDUWlWbmtoQmt0VWdnPT0iLAogICAgICAgICAgICAgICAgImtleURldGFpbHMiOiAiUEtJWF9FQ0RTQV9QMjU2X1NIQV8yNTYiLAogICAgICAgICAgICAgICAgInZhbGlkRm9yIjogewogICAgICAgICAgICAgICAgICAgICJzdGFydCI6ICIyMDIyLTEyLTAxVDAwOjAwOjAwLjAwMFoiCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICBdCn0K', + }, + }, +}; diff --git a/packages/tuf/store/public-good-instance-root.json b/packages/tuf/store/public-good-instance-root.json deleted file mode 100644 index e95c7e88c..000000000 --- a/packages/tuf/store/public-good-instance-root.json +++ /dev/null @@ -1 +0,0 @@ -{"signed":{"_type":"root","spec_version":"1.0","version":7,"expires":"2023-10-04T13:08:11Z","keys":{"25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEXsz3SZXFb8jMV42j6pJlyjbjR8K\nN3Bwocexq6LMIb5qsWKOQvLN16NUefLc4HswOoumRsVVaajSpQS6fobkRw==\n-----END PUBLIC KEY-----\n"}},"2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0ghrh92Lw1Yr3idGV5WqCtMDB8Cx\n+D8hdC4w2ZLNIplVRoVGLskYa3gheMyOjiJ8kPi15aQ2//7P+oj7UvJPGw==\n-----END PUBLIC KEY-----\n"}},"45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELrWvNt94v4R085ELeeCMxHp7PldF\n0/T1GxukUh2ODuggLGJE0pc1e8CSBf6CS91Fwo9FUOuRsjBUld+VqSyCdQ==\n-----END PUBLIC KEY-----\n"}},"7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEinikSsAQmYkNeH5eYq/CnIzLaacO\nxlSaawQDOwqKy/tCqxq5xxPSJc21K4WIhs9GyOkKfzueY3GILzcMJZ4cWw==\n-----END PUBLIC KEY-----\n"}},"e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWRiGr5+j+3J5SsH+Ztr5nE2H2wO7\nBV+nO3s93gLca18qTOzHY1oWyAGDykMSsGTUBSt9D+An0KfKsD2mfSM42Q==\n-----END PUBLIC KEY-----\n"}},"f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzBzVOmHCPojMVLSI364WiiV8NPrD\n6IgRxVliskz/v+y3JER5mcVGcONliDcWMC5J2lfHmjPNPhb4H7xm8LzfSA==\n-----END PUBLIC KEY-----\n"}},"ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEy8XKsmhBYDI8Jc0GwzBxeKax0cm5\nSTKEU65HPFunUn41sT8pi0FjM4IkHz/YUmwmLUO0Wt7lxhj6BkLIK4qYAw==\n-----END PUBLIC KEY-----\n"}}},"roles":{"root":{"keyids":["ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c","25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f","7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de"],"threshold":3},"snapshot":{"keyids":["45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b"],"threshold":1},"targets":{"keyids":["ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c","25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f","7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de"],"threshold":3},"timestamp":{"keyids":["e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a"],"threshold":1}},"consistent_snapshot":true},"signatures":[{"keyid":"25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","sig":"3046022100c0610c0055ce5c4a52d054d7322e7b514d55baf44423d63aa4daa077cc60fd1f022100a097f2803f090fb66c42ead915a2c46ebe7db53a32bf18f2188275cc936f8bdd"},{"keyid":"f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f","sig":"304502203134f0468810299d5493a867c40630b341296b92e59c29821311d353343bb3a4022100e667ae3d304e7e3da0894c7425f6b9ecd917106841280e5cf6f3496ad5f8f68e"},{"keyid":"7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","sig":"3045022037fe5f45426f21eaaf4730d2136f2b1611d6379688f79b9d1e3f61719997135c022100b63b022d7b79d4694b96f416d88aa4d7b1a3bff8a01f4fb51e0f42137c7d2d06"},{"keyid":"2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de","sig":"3044022007cc8fcc4940809f2751ad5b535f4c5f53f5b4952f5b5696b09668e743306ac1022006dfcdf94e94c92163eeb1b47796db62cedaa730aa13aa61b573fe23714730f2"}]}