mirror of
https://github.com/expo/eas-cli.git
synced 2026-11-14 10:08:06 -10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72b8a78145 |
No files matched your search
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@expo/build-tools': patch
|
||||
---
|
||||
|
||||
Retry the build lookup and the archive download of `eas/download_build` on transient failures, and name the failure cause in the build log.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'eas-cli': none
|
||||
---
|
||||
|
||||
Make command descriptions in `eas --help` consistently lowercase without trailing periods.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
'eas-cli': none
|
||||
'@expo/build-tools': none
|
||||
---
|
||||
|
||||
Bump Node.js to 22.23.4 to fix the CVEs in the [October 2026 Node.js security releases](https://nodejs.org/en/blog/vulnerability/october-2026-security-releases).
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@expo/build-tools': minor
|
||||
---
|
||||
|
||||
Stop sandboxes after an optional maximum duration measured from readiness.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@expo/worker': patch
|
||||
---
|
||||
|
||||
Apply the job log's secret masking to uploaded Xcode build logs.
|
||||
@@ -6,4 +6,4 @@ MISE_NODE_COREPACK = "true"
|
||||
actionlint = "1.7.12"
|
||||
gcloud = "570.0.0"
|
||||
jq = "1.8.1"
|
||||
node = "22.23.4"
|
||||
node = "22.23.3"
|
||||
@@ -26,7 +26,7 @@
|
||||
"build:egress-guard": "resources/egress-guard/build.sh",
|
||||
"test:egress-guard": "resources/egress-guard/tests/run-policy-tests.sh && resources/egress-guard/tests/run-guard-tests.sh",
|
||||
"typecheck": "tsc",
|
||||
"generate-appium-commands": "mise exec [email protected]3.4 -- node scripts/generate-appium-commands.js",
|
||||
"generate-appium-commands": "mise exec [email protected]2.0 -- node scripts/generate-appium-commands.js",
|
||||
"prepack": "rimraf dist \"*.tsbuildinfo\" && yarn gql && tsc -p tsconfig.build.json",
|
||||
"jest-unit": "jest --config jest/unit-config.ts",
|
||||
"jest-integration": "jest --config jest/integration-config.ts",
|
||||
|
||||
@@ -11,7 +11,6 @@ import * as tar from 'tar';
|
||||
|
||||
import { createGlobalContextMock } from '../../../__tests__/utils/context';
|
||||
import { createMockLogger } from '../../../__tests__/utils/logger';
|
||||
import { Datadog } from '../../../datadog';
|
||||
import * as files from '../../../utils/files';
|
||||
import { createDownloadBuildFunction, downloadBuildAsync } from '../downloadBuild';
|
||||
|
||||
@@ -31,17 +30,11 @@ const APPLICATION_ARCHIVE_URL = `https://expo.dev/artifacts/eas/${randomUUID()}.
|
||||
function createMockGraphqlClient({
|
||||
applicationArchiveUrl,
|
||||
error,
|
||||
transientError,
|
||||
}: {
|
||||
applicationArchiveUrl?: string | null;
|
||||
error?: Error;
|
||||
transientError?: Error;
|
||||
}): Client {
|
||||
const toPromise = jest.fn();
|
||||
if (transientError) {
|
||||
toPromise.mockResolvedValueOnce({ error: transientError, data: undefined });
|
||||
}
|
||||
toPromise.mockResolvedValue(
|
||||
const toPromise = jest.fn().mockResolvedValue(
|
||||
error
|
||||
? { error, data: undefined }
|
||||
: {
|
||||
@@ -69,7 +62,7 @@ function createSuccessfulResponse({
|
||||
url,
|
||||
headers,
|
||||
}: {
|
||||
body: Buffer | Readable;
|
||||
body: Buffer;
|
||||
url: string;
|
||||
headers?: Record<string, string>;
|
||||
}): Response {
|
||||
@@ -79,7 +72,7 @@ function createSuccessfulResponse({
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
body: body instanceof Readable ? body : Readable.from(body),
|
||||
body: Readable.from(body),
|
||||
url,
|
||||
headers: {
|
||||
get: (name: string): string | null => normalizedHeaders[name.toLowerCase()] ?? null,
|
||||
@@ -87,47 +80,6 @@ function createSuccessfulResponse({
|
||||
} as unknown as Response;
|
||||
}
|
||||
|
||||
function createUndiciNetworkError(code: string): CombinedError {
|
||||
return new CombinedError({
|
||||
networkError: Object.assign(new TypeError('fetch failed'), {
|
||||
cause: Object.assign(new Error(`read ${code}`), { code }),
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
const { FetchError: ActualFetchError } = jest.requireActual(
|
||||
'node-fetch'
|
||||
) as typeof import('node-fetch');
|
||||
|
||||
function createSocketFetchError(url: string, code: string): Error {
|
||||
return new ActualFetchError(`request to ${url} failed, reason: connect ${code}`, 'system', {
|
||||
code,
|
||||
} as any);
|
||||
}
|
||||
|
||||
function useFakeBackoffTimers(): void {
|
||||
// Streams and fs callbacks need the real nextTick and setImmediate; only the backoff timers are faked.
|
||||
jest.useFakeTimers({ doNotFake: ['nextTick', 'setImmediate', 'queueMicrotask'] });
|
||||
}
|
||||
|
||||
const MAX_IO_TURNS_BEFORE_BACKOFF = 1000;
|
||||
|
||||
async function waitForBackoffTimerAsync(): Promise<void> {
|
||||
for (let turns = 0; jest.getTimerCount() === 0; turns++) {
|
||||
if (turns === MAX_IO_TURNS_BEFORE_BACKOFF) {
|
||||
throw new Error('No backoff timer was scheduled.');
|
||||
}
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
}
|
||||
}
|
||||
|
||||
async function fireBackoffTimersAsync(count: number): Promise<void> {
|
||||
for (let i = 0; i < count; i++) {
|
||||
await waitForBackoffTimerAsync();
|
||||
await jest.advanceTimersToNextTimerAsync();
|
||||
}
|
||||
}
|
||||
|
||||
async function createFlatAppTarGzBufferAsync(): Promise<Buffer> {
|
||||
const sourceDirectory = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'flat-app-source-'));
|
||||
const archivePath = path.join(os.tmpdir(), `${randomUUID()}.tar.gz`);
|
||||
@@ -156,11 +108,6 @@ async function createFlatAppTarGzBufferAsync(): Promise<Buffer> {
|
||||
}
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
jest.useRealTimers();
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('downloadBuild', () => {
|
||||
it('downloads from applicationArchiveUrl returned by GraphQL', async () => {
|
||||
const buildId = randomUUID();
|
||||
@@ -518,13 +465,13 @@ describe('downloadBuild', () => {
|
||||
expect(jest.mocked(fetch)).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('throws SystemError with the cause code after retrying a failing build lookup', async () => {
|
||||
useFakeBackoffTimers();
|
||||
it('throws SystemError when GraphQL request fails with a network error', async () => {
|
||||
const buildId = randomUUID();
|
||||
const graphqlClient = createMockGraphqlClient({
|
||||
error: createUndiciNetworkError('ECONNRESET'),
|
||||
error: new CombinedError({
|
||||
networkError: new Error('Network request failed'),
|
||||
}),
|
||||
});
|
||||
const datadogLog = jest.spyOn(Datadog, 'log');
|
||||
|
||||
const promise = downloadBuildAsync({
|
||||
logger: createLogger({ name: 'test' }),
|
||||
@@ -533,81 +480,19 @@ describe('downloadBuild', () => {
|
||||
robotAccessToken: null,
|
||||
extensions: ['app'],
|
||||
});
|
||||
const rejection = expect(promise).rejects.toBeInstanceOf(SystemError);
|
||||
await fireBackoffTimersAsync(5);
|
||||
|
||||
await rejection;
|
||||
await expect(promise).rejects.toBeInstanceOf(SystemError);
|
||||
await expect(promise).rejects.toMatchObject({
|
||||
message: `Could not fetch build ${buildId}: [Network] fetch failed (ECONNRESET)`,
|
||||
});
|
||||
expect(graphqlClient.query).toHaveBeenCalledTimes(6);
|
||||
expect(datadogLog).toHaveBeenCalledWith('download_build.build_lookup failed on attempt 6', {
|
||||
event: 'network_retry',
|
||||
operation: 'download_build.build_lookup',
|
||||
outcome: 'failed',
|
||||
attempts: '6',
|
||||
code: 'ECONNRESET',
|
||||
message: `Could not fetch build ${buildId}: [Network] Network request failed`,
|
||||
});
|
||||
|
||||
expect(jest.mocked(fetch)).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it.each([
|
||||
['a network error', createUndiciNetworkError('ECONNRESET'), 'ECONNRESET'],
|
||||
[
|
||||
'a transient GraphQL error',
|
||||
new CombinedError({
|
||||
graphQLErrors: [
|
||||
{
|
||||
message: 'Too many requests',
|
||||
extensions: { isTransient: true, errorCode: 'TOO_MANY_REQUESTS' },
|
||||
},
|
||||
],
|
||||
response: { status: 200 },
|
||||
}),
|
||||
'TOO_MANY_REQUESTS',
|
||||
],
|
||||
])('downloads after a build lookup that failed once with %s', async (_, transientError, code) => {
|
||||
useFakeBackoffTimers();
|
||||
const buildId = randomUUID();
|
||||
const graphqlClient = createMockGraphqlClient({
|
||||
applicationArchiveUrl: APPLICATION_ARCHIVE_URL,
|
||||
transientError,
|
||||
});
|
||||
jest
|
||||
.mocked(fetch)
|
||||
.mockResolvedValue(
|
||||
createSuccessfulResponse({ body: Buffer.from('hello'), url: 'https://cdn.test/app.apk' })
|
||||
);
|
||||
|
||||
const datadogLog = jest.spyOn(Datadog, 'log');
|
||||
|
||||
const promise = downloadBuildAsync({
|
||||
logger: createLogger({ name: 'test' }),
|
||||
buildId,
|
||||
graphqlClient,
|
||||
robotAccessToken: null,
|
||||
extensions: ['apk'],
|
||||
});
|
||||
await fireBackoffTimersAsync(1);
|
||||
|
||||
const { artifactPath } = await promise;
|
||||
expect(path.basename(artifactPath)).toBe('app.apk');
|
||||
expect(graphqlClient.query).toHaveBeenCalledTimes(2);
|
||||
expect(datadogLog).toHaveBeenCalledWith('download_build.build_lookup recovered on attempt 2', {
|
||||
event: 'network_retry',
|
||||
operation: 'download_build.build_lookup',
|
||||
outcome: 'recovered',
|
||||
attempts: '2',
|
||||
code,
|
||||
});
|
||||
});
|
||||
|
||||
it('throws SystemError when GraphQL request returns 5xx', async () => {
|
||||
useFakeBackoffTimers();
|
||||
const buildId = randomUUID();
|
||||
const graphqlClient = createMockGraphqlClient({
|
||||
error: new CombinedError({
|
||||
graphQLErrors: [{ message: 'Internal Server Error' }],
|
||||
error: Object.assign(new Error('Internal Server Error'), {
|
||||
response: { status: 500 },
|
||||
}),
|
||||
});
|
||||
@@ -619,14 +504,12 @@ describe('downloadBuild', () => {
|
||||
robotAccessToken: null,
|
||||
extensions: ['app'],
|
||||
});
|
||||
const rejection = expect(promise).rejects.toBeInstanceOf(SystemError);
|
||||
await fireBackoffTimersAsync(5);
|
||||
|
||||
await rejection;
|
||||
await expect(promise).rejects.toBeInstanceOf(SystemError);
|
||||
await expect(promise).rejects.toMatchObject({
|
||||
message: `Could not fetch build ${buildId}: [GraphQL] Internal Server Error`,
|
||||
message: `Could not fetch build ${buildId}: Internal Server Error`,
|
||||
});
|
||||
expect(graphqlClient.query).toHaveBeenCalledTimes(6);
|
||||
|
||||
expect(jest.mocked(fetch)).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -651,193 +534,10 @@ describe('downloadBuild', () => {
|
||||
errorCode: 'EAS_DOWNLOAD_BUILD_FETCH_FAILED',
|
||||
message: `Could not fetch build ${buildId}: [GraphQL] Build not found`,
|
||||
});
|
||||
expect(graphqlClient.query).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(jest.mocked(fetch)).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('downloads after an archive request that failed once with a socket error', async () => {
|
||||
useFakeBackoffTimers();
|
||||
const graphqlClient = createMockGraphqlClient({});
|
||||
jest
|
||||
.mocked(fetch)
|
||||
.mockRejectedValueOnce(createSocketFetchError(APPLICATION_ARCHIVE_URL, 'ECONNRESET'))
|
||||
.mockResolvedValueOnce(
|
||||
createSuccessfulResponse({ body: Buffer.from('hello'), url: 'https://cdn.test/app.apk' })
|
||||
);
|
||||
|
||||
const promise = downloadBuildAsync({
|
||||
logger: createLogger({ name: 'test' }),
|
||||
applicationArchiveUrl: APPLICATION_ARCHIVE_URL,
|
||||
graphqlClient,
|
||||
robotAccessToken: null,
|
||||
extensions: ['apk'],
|
||||
});
|
||||
await fireBackoffTimersAsync(1);
|
||||
|
||||
const { artifactPath } = await promise;
|
||||
expect(path.basename(artifactPath)).toBe('app.apk');
|
||||
expect(jest.mocked(fetch)).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('throws SystemError with the cause code after retrying a failing build archive request', async () => {
|
||||
useFakeBackoffTimers();
|
||||
const graphqlClient = createMockGraphqlClient({
|
||||
applicationArchiveUrl: APPLICATION_ARCHIVE_URL,
|
||||
});
|
||||
jest
|
||||
.mocked(fetch)
|
||||
.mockRejectedValue(createSocketFetchError(APPLICATION_ARCHIVE_URL, 'ETIMEDOUT'));
|
||||
const datadogLog = jest.spyOn(Datadog, 'log');
|
||||
|
||||
const promise = downloadBuildAsync({
|
||||
logger: createLogger({ name: 'test' }),
|
||||
buildId: randomUUID(),
|
||||
graphqlClient,
|
||||
robotAccessToken: null,
|
||||
extensions: ['apk'],
|
||||
});
|
||||
const rejection = expect(promise).rejects.toBeInstanceOf(SystemError);
|
||||
await fireBackoffTimersAsync(5);
|
||||
|
||||
await rejection;
|
||||
await expect(promise).rejects.toMatchObject({
|
||||
message: `Could not download the application archive: request to ${APPLICATION_ARCHIVE_URL} failed, reason: connect ETIMEDOUT`,
|
||||
});
|
||||
expect(jest.mocked(fetch)).toHaveBeenCalledTimes(6);
|
||||
expect(datadogLog).toHaveBeenCalledWith('download_build.archive_download failed on attempt 6', {
|
||||
event: 'network_retry',
|
||||
operation: 'download_build.archive_download',
|
||||
outcome: 'failed',
|
||||
attempts: '6',
|
||||
code: 'ETIMEDOUT',
|
||||
});
|
||||
});
|
||||
|
||||
function createBrokenBody(code: string): Readable {
|
||||
return Readable.from(
|
||||
(async function* () {
|
||||
yield Buffer.from('he');
|
||||
throw Object.assign(new Error(`body failed with ${code}`), { code });
|
||||
})()
|
||||
);
|
||||
}
|
||||
|
||||
it.each(['ERR_STREAM_PREMATURE_CLOSE', 'ECONNRESET'])(
|
||||
'downloads again when the archive body breaks off with %s after the headers arrived',
|
||||
async code => {
|
||||
useFakeBackoffTimers();
|
||||
const graphqlClient = createMockGraphqlClient({});
|
||||
const brokenBody = createBrokenBody(code);
|
||||
jest
|
||||
.mocked(fetch)
|
||||
.mockResolvedValueOnce(
|
||||
createSuccessfulResponse({ body: brokenBody, url: 'https://cdn.test/app.apk' })
|
||||
)
|
||||
.mockResolvedValueOnce(
|
||||
createSuccessfulResponse({ body: Buffer.from('hello'), url: 'https://cdn.test/app.apk' })
|
||||
);
|
||||
const datadogLog = jest.spyOn(Datadog, 'log');
|
||||
|
||||
const promise = downloadBuildAsync({
|
||||
logger: createLogger({ name: 'test' }),
|
||||
applicationArchiveUrl: APPLICATION_ARCHIVE_URL,
|
||||
graphqlClient,
|
||||
robotAccessToken: null,
|
||||
extensions: ['apk'],
|
||||
});
|
||||
await fireBackoffTimersAsync(1);
|
||||
|
||||
const { artifactPath } = await promise;
|
||||
expect(await fs.promises.readFile(artifactPath, 'utf-8')).toBe('hello');
|
||||
expect(jest.mocked(fetch)).toHaveBeenCalledTimes(2);
|
||||
expect(datadogLog).toHaveBeenCalledWith(
|
||||
'download_build.archive_download recovered on attempt 2',
|
||||
expect.objectContaining({ outcome: 'recovered', code })
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
it('throws SystemError when the build archive body keeps breaking off', async () => {
|
||||
useFakeBackoffTimers();
|
||||
const graphqlClient = createMockGraphqlClient({
|
||||
applicationArchiveUrl: APPLICATION_ARCHIVE_URL,
|
||||
});
|
||||
jest.mocked(fetch).mockImplementation(async () =>
|
||||
createSuccessfulResponse({
|
||||
body: createBrokenBody('ECONNRESET'),
|
||||
url: 'https://cdn.test/app.apk',
|
||||
})
|
||||
);
|
||||
const datadogLog = jest.spyOn(Datadog, 'log');
|
||||
|
||||
const promise = downloadBuildAsync({
|
||||
logger: createLogger({ name: 'test' }),
|
||||
buildId: randomUUID(),
|
||||
graphqlClient,
|
||||
robotAccessToken: null,
|
||||
extensions: ['apk'],
|
||||
});
|
||||
const rejection = expect(promise).rejects.toBeInstanceOf(SystemError);
|
||||
await fireBackoffTimersAsync(5);
|
||||
|
||||
await rejection;
|
||||
await expect(promise).rejects.toMatchObject({
|
||||
message: 'Could not download the application archive: body failed with ECONNRESET',
|
||||
});
|
||||
expect(jest.mocked(fetch)).toHaveBeenCalledTimes(6);
|
||||
expect(datadogLog).toHaveBeenCalledWith(
|
||||
'download_build.archive_download failed on attempt 6',
|
||||
expect.objectContaining({ outcome: 'failed', code: 'ECONNRESET' })
|
||||
);
|
||||
});
|
||||
|
||||
it('does not start another archive attempt after an abort during the backoff', async () => {
|
||||
useFakeBackoffTimers();
|
||||
const graphqlClient = createMockGraphqlClient({});
|
||||
jest
|
||||
.mocked(fetch)
|
||||
.mockRejectedValueOnce(createSocketFetchError(APPLICATION_ARCHIVE_URL, 'ECONNRESET'));
|
||||
const controller = new AbortController();
|
||||
const reason = new Error('step timed out');
|
||||
|
||||
const promise = downloadBuildAsync({
|
||||
logger: createLogger({ name: 'test' }),
|
||||
applicationArchiveUrl: APPLICATION_ARCHIVE_URL,
|
||||
graphqlClient,
|
||||
robotAccessToken: null,
|
||||
extensions: ['apk'],
|
||||
signal: controller.signal,
|
||||
});
|
||||
const rejection = expect(promise).rejects.toBe(reason);
|
||||
await waitForBackoffTimerAsync();
|
||||
controller.abort(reason);
|
||||
await jest.advanceTimersToNextTimerAsync();
|
||||
|
||||
await rejection;
|
||||
expect(jest.mocked(fetch)).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('rethrows the raw error of a failing user-supplied archive URL after the retries', async () => {
|
||||
useFakeBackoffTimers();
|
||||
const graphqlClient = createMockGraphqlClient({});
|
||||
jest
|
||||
.mocked(fetch)
|
||||
.mockRejectedValue(createSocketFetchError(APPLICATION_ARCHIVE_URL, 'ENOTFOUND'));
|
||||
|
||||
const promise = downloadBuildAsync({
|
||||
logger: createLogger({ name: 'test' }),
|
||||
applicationArchiveUrl: APPLICATION_ARCHIVE_URL,
|
||||
graphqlClient,
|
||||
robotAccessToken: null,
|
||||
extensions: ['apk'],
|
||||
});
|
||||
const rejection = expect(promise).rejects.toBeInstanceOf(ActualFetchError);
|
||||
await fireBackoffTimersAsync(5);
|
||||
|
||||
await rejection;
|
||||
expect(jest.mocked(fetch)).toHaveBeenCalledTimes(6);
|
||||
});
|
||||
|
||||
it('should throw an error if no matching files are found', async () => {
|
||||
const graphqlClient = createMockGraphqlClient({
|
||||
applicationArchiveUrl: APPLICATION_ARCHIVE_URL,
|
||||
@@ -905,21 +605,6 @@ describe('createDownloadBuildFunction', () => {
|
||||
};
|
||||
}
|
||||
|
||||
function createApplicationResponse(buildId: string): Response {
|
||||
return new ActualResponse(
|
||||
JSON.stringify({
|
||||
data: {
|
||||
build: {
|
||||
id: buildId,
|
||||
gitCommitHash: null,
|
||||
applicationArchiveUrl: APPLICATION_ARCHIVE_URL,
|
||||
},
|
||||
},
|
||||
}),
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
|
||||
function createStep(ctx: any, callInputs: Record<string, unknown>) {
|
||||
return createDownloadBuildFunction(ctx).createBuildStepFromFunctionCall(
|
||||
createGlobalContextMock({
|
||||
@@ -935,7 +620,18 @@ describe('createDownloadBuildFunction', () => {
|
||||
const graphqlClient = createMockGraphqlClient({});
|
||||
jest.mocked(fetch).mockImplementation(async url => {
|
||||
if (url === workerApiUrl) {
|
||||
return createApplicationResponse(buildId);
|
||||
return new ActualResponse(
|
||||
JSON.stringify({
|
||||
data: {
|
||||
build: {
|
||||
id: buildId,
|
||||
gitCommitHash: null,
|
||||
applicationArchiveUrl: APPLICATION_ARCHIVE_URL,
|
||||
},
|
||||
},
|
||||
}),
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
return {
|
||||
ok: false,
|
||||
@@ -965,33 +661,6 @@ describe('createDownloadBuildFunction', () => {
|
||||
expect(graphqlClient.query).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('retries the worker API lookup after a 5xx response', async () => {
|
||||
useFakeBackoffTimers();
|
||||
const buildId = randomUUID();
|
||||
const graphqlClient = createMockGraphqlClient({});
|
||||
jest
|
||||
.mocked(fetch)
|
||||
.mockResolvedValueOnce(new ActualResponse('Service Unavailable', { status: 503 }))
|
||||
.mockResolvedValueOnce(createApplicationResponse(buildId))
|
||||
.mockResolvedValueOnce(
|
||||
createSuccessfulResponse({ body: Buffer.from('hello'), url: 'https://cdn.test/app.apk' })
|
||||
);
|
||||
|
||||
const execution = createStep(createSessionCtx(graphqlClient), {
|
||||
build_id: buildId,
|
||||
extensions: ['apk'],
|
||||
}).executeAsync();
|
||||
await fireBackoffTimersAsync(1);
|
||||
|
||||
await execution;
|
||||
expect(jest.mocked(fetch)).toHaveBeenCalledTimes(3);
|
||||
expect(jest.mocked(fetch).mock.calls.map(([url]) => url)).toEqual([
|
||||
workerApiUrl,
|
||||
workerApiUrl,
|
||||
APPLICATION_ARCHIVE_URL,
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not call the worker API for an application_archive_url input', async () => {
|
||||
const graphqlClient = createMockGraphqlClient({});
|
||||
jest.mocked(fetch).mockResolvedValue({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SystemError, UserError } from '@expo/eas-build-job';
|
||||
import { SystemError } from '@expo/eas-build-job';
|
||||
import { Client, fetchExchange } from '@urql/core';
|
||||
|
||||
import * as sandboxDaemon from '../../utils/sandboxDaemon';
|
||||
@@ -6,90 +6,6 @@ import * as sandboxDaemon from '../../utils/sandboxDaemon';
|
||||
import { createStartSandboxBuildFunction, markSandboxReadyAsync } from '../startSandbox';
|
||||
|
||||
describe('sandbox build functions', () => {
|
||||
it.each([
|
||||
{ completion: 'duration', duration: 0.02 },
|
||||
{ completion: 'cancellation', duration: 60 },
|
||||
{ completion: 'duration', duration: 0.0001 },
|
||||
])(
|
||||
'stops after $completion with $duration seconds only after readiness',
|
||||
async ({ completion, duration }) => {
|
||||
const controller = new AbortController();
|
||||
let ready!: () => void;
|
||||
const stopAsync = jest.fn(async () => {});
|
||||
const start = jest.spyOn(sandboxDaemon, 'startSandboxDaemonAsync').mockResolvedValue({
|
||||
ready: new Promise<void>(resolve => {
|
||||
ready = resolve;
|
||||
}),
|
||||
stopAsync,
|
||||
});
|
||||
const mutation = jest.fn(() => ({ toPromise: async () => ({ data: {} }) }));
|
||||
const logger = { info: jest.fn(), child: jest.fn() };
|
||||
logger.child.mockReturnValue(logger);
|
||||
const fn = createStartSandboxBuildFunction({
|
||||
mcpServerUrl: 'ws://localhost:8787',
|
||||
graphqlClient: { mutation },
|
||||
} as any);
|
||||
try {
|
||||
const pending = fn.fn!({ logger } as any, {
|
||||
inputs: {
|
||||
sandbox_id: { value: 'sandbox-id' },
|
||||
max_duration_seconds: { value: duration },
|
||||
},
|
||||
outputs: {},
|
||||
env: { __EAS_SANDBOX_MCP_TOKEN: 'token' },
|
||||
signal: controller.signal,
|
||||
});
|
||||
await new Promise(resolve => setTimeout(resolve, 40));
|
||||
expect(mutation).not.toHaveBeenCalled();
|
||||
expect(stopAsync).not.toHaveBeenCalled();
|
||||
ready();
|
||||
if (completion === 'cancellation') {
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
expect(stopAsync).not.toHaveBeenCalled();
|
||||
controller.abort();
|
||||
}
|
||||
await pending;
|
||||
expect(mutation).toHaveBeenCalledTimes(1);
|
||||
expect(stopAsync).toHaveBeenCalledTimes(1);
|
||||
const timeoutMessage = `Sandbox reached its maximum runtime of ${duration} seconds. Stopping.`;
|
||||
if (completion === 'duration') {
|
||||
expect(logger.info).toHaveBeenCalledWith(timeoutMessage);
|
||||
} else {
|
||||
expect(logger.info).not.toHaveBeenCalledWith(timeoutMessage);
|
||||
}
|
||||
} finally {
|
||||
start.mockRestore();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
it.each([0, -1, Infinity, NaN])(
|
||||
'rejects invalid maximum duration %s before starting the daemon',
|
||||
async duration => {
|
||||
const start = jest.spyOn(sandboxDaemon, 'startSandboxDaemonAsync');
|
||||
const fn = createStartSandboxBuildFunction({
|
||||
mcpServerUrl: 'ws://localhost:8787',
|
||||
} as any);
|
||||
try {
|
||||
const result = fn.fn!({} as any, {
|
||||
inputs: {
|
||||
sandbox_id: { value: 'sandbox-id' },
|
||||
max_duration_seconds: { value: duration },
|
||||
},
|
||||
outputs: {},
|
||||
env: { __EAS_SANDBOX_MCP_TOKEN: 'token' },
|
||||
});
|
||||
await expect(result).rejects.toBeInstanceOf(UserError);
|
||||
await expect(result).rejects.toThrow(
|
||||
`Invalid sandbox maximum duration: ${duration}. Provide a finite number greater than zero, or omit max_duration_seconds.`
|
||||
);
|
||||
expect(start).not.toHaveBeenCalled();
|
||||
} finally {
|
||||
start.mockRestore();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
it('aborts an active ready request and keeps its authentication headers', async () => {
|
||||
const controller = new AbortController();
|
||||
let requestStarted!: () => void;
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
BuildStepInputValueTypeName,
|
||||
BuildStepOutput,
|
||||
} from '@expo/steps';
|
||||
import { Client, CombinedError } from '@urql/core';
|
||||
import { Client } from '@urql/core';
|
||||
import contentDisposition from 'content-disposition';
|
||||
import { glob } from 'fast-glob';
|
||||
import { graphql } from 'gql.tada';
|
||||
@@ -26,16 +26,10 @@ import { CustomBuildContext } from '../../customBuildContext';
|
||||
import { formatBytes } from '../../utils/artifacts';
|
||||
import { decompressTarAsync, isFileTarGzAsync } from '../../utils/files';
|
||||
import { graphqlAbortContext } from '../../utils/graphqlAbort';
|
||||
import {
|
||||
describeError,
|
||||
isTransferFailure,
|
||||
isTransientGraphqlError,
|
||||
} from '../../utils/networkErrors';
|
||||
import { retryOnNetworkFailureAsync } from '../../utils/retryOnNetworkFailure';
|
||||
import { retryOnDNSFailure } from '../../utils/retryOnDNSFailure';
|
||||
import { pluralize } from '../../utils/strings';
|
||||
import {
|
||||
type DeviceRunSessionWorkerApi,
|
||||
DeviceRunSessionWorkerApiError,
|
||||
getDeviceRunSessionWorkerApi,
|
||||
} from '../utils/deviceRunSessionWorkerApi';
|
||||
|
||||
@@ -158,34 +152,21 @@ async function fetchApplicationArchiveUrlAsync({
|
||||
signal,
|
||||
});
|
||||
}
|
||||
let data;
|
||||
try {
|
||||
data = await retryOnNetworkFailureAsync(
|
||||
async () => {
|
||||
const queryResult = await graphqlClient
|
||||
.query(BUILD_BY_ID_QUERY, { buildId }, graphqlAbortContext(signal))
|
||||
.toPromise();
|
||||
if (queryResult.error) {
|
||||
throw queryResult.error;
|
||||
}
|
||||
return queryResult.data;
|
||||
},
|
||||
{
|
||||
operation: 'download_build.build_lookup',
|
||||
signal,
|
||||
isRetryable: error => error instanceof CombinedError && isTransientGraphqlError(error),
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
signal?.throwIfAborted();
|
||||
const message = `Could not fetch build ${buildId}: ${describeError(error)}`;
|
||||
throw error instanceof CombinedError && !isTransientGraphqlError(error)
|
||||
? new UserError('EAS_DOWNLOAD_BUILD_FETCH_FAILED', message, { cause: error })
|
||||
: new SystemError(message, { cause: error });
|
||||
}
|
||||
const result = await graphqlClient
|
||||
.query(BUILD_BY_ID_QUERY, { buildId }, graphqlAbortContext(signal))
|
||||
.toPromise();
|
||||
signal?.throwIfAborted();
|
||||
|
||||
const applicationArchiveUrl = data?.builds.byId?.artifacts?.applicationArchiveUrl;
|
||||
if (result.error) {
|
||||
const { error } = result;
|
||||
const message = `Could not fetch build ${buildId}: ${error.message}`;
|
||||
|
||||
throw error.networkError || result.error.response?.status >= 500
|
||||
? new SystemError(message, { cause: error })
|
||||
: new UserError('EAS_DOWNLOAD_BUILD_FETCH_FAILED', message, { cause: error });
|
||||
}
|
||||
|
||||
const applicationArchiveUrl = result.data?.builds.byId?.artifacts?.applicationArchiveUrl;
|
||||
if (!applicationArchiveUrl) {
|
||||
throw new UserError(
|
||||
'EAS_DOWNLOAD_BUILD_NO_APPLICATION_ARCHIVE',
|
||||
@@ -214,18 +195,13 @@ async function fetchDeviceRunSessionApplicationArchiveUrlAsync({
|
||||
}): Promise<string> {
|
||||
let application;
|
||||
try {
|
||||
application = await retryOnNetworkFailureAsync(
|
||||
() => deviceRunSessionWorkerApi.getApplicationAsync({ signal }),
|
||||
{
|
||||
operation: 'download_build.session_build_lookup',
|
||||
signal,
|
||||
isRetryable: error => error instanceof DeviceRunSessionWorkerApiError && error.isTransient,
|
||||
}
|
||||
);
|
||||
application = await deviceRunSessionWorkerApi.getApplicationAsync({ signal });
|
||||
} catch (err) {
|
||||
signal?.throwIfAborted();
|
||||
throw new SystemError(
|
||||
`Could not fetch build ${buildId} for this device run session: ${describeError(err)}`,
|
||||
`Could not fetch build ${buildId} for this device run session: ${
|
||||
err instanceof Error ? err.message : String(err)
|
||||
}`,
|
||||
{ cause: err }
|
||||
);
|
||||
}
|
||||
@@ -305,34 +281,18 @@ export async function downloadBuildAsync(
|
||||
);
|
||||
|
||||
signal?.throwIfAborted();
|
||||
let archivePath: string;
|
||||
try {
|
||||
archivePath = await retryOnNetworkFailureAsync(
|
||||
async () => {
|
||||
const response = await fetch(downloadUrl, { headers, signal });
|
||||
if (!response.ok) {
|
||||
const textResult = await asyncResult(response.text());
|
||||
throw new Error(
|
||||
`Unexpected response from server (${response.status}): ${textResult.value}`
|
||||
);
|
||||
}
|
||||
const archiveFilename = resolveArchiveFilename({ response, extensions });
|
||||
const attemptArchivePath = path.join(downloadDestinationDirectory, archiveFilename);
|
||||
// On abort, node-fetch emits an error on the body stream, which fails the pipeline.
|
||||
await streamPipeline(response.body, fs.createWriteStream(attemptArchivePath));
|
||||
return attemptArchivePath;
|
||||
},
|
||||
{ operation: 'download_build.archive_download', signal, isRetryable: isTransferFailure }
|
||||
);
|
||||
} catch (error) {
|
||||
signal?.throwIfAborted();
|
||||
if (params.buildId && isTransferFailure(error)) {
|
||||
throw new SystemError(`Could not download the application archive: ${describeError(error)}`, {
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
const response = await retryOnDNSFailure(fetch)(downloadUrl, { headers, signal });
|
||||
|
||||
if (!response.ok) {
|
||||
const textResult = await asyncResult(response.text());
|
||||
throw new Error(`Unexpected response from server (${response.status}): ${textResult.value}`);
|
||||
}
|
||||
|
||||
const archiveFilename = resolveArchiveFilename({ response, extensions });
|
||||
const archivePath = path.join(downloadDestinationDirectory, archiveFilename);
|
||||
|
||||
// On abort, node-fetch emits an error on the body stream, which fails the pipeline.
|
||||
await streamPipeline(response.body, fs.createWriteStream(archivePath));
|
||||
signal?.throwIfAborted();
|
||||
|
||||
const { size } = await fs.promises.stat(archivePath);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SystemError, UserError } from '@expo/eas-build-job';
|
||||
import { SystemError } from '@expo/eas-build-job';
|
||||
import { BuildFunction, BuildStepInput, BuildStepInputValueTypeName } from '@expo/steps';
|
||||
import { graphql } from 'gql.tada';
|
||||
|
||||
@@ -32,11 +32,6 @@ export function createStartSandboxBuildFunction(ctx: CustomBuildContext): BuildF
|
||||
required: true,
|
||||
allowedValueTypeName: BuildStepInputValueTypeName.STRING,
|
||||
}),
|
||||
BuildStepInput.createProvider({
|
||||
id: 'max_duration_seconds',
|
||||
required: false,
|
||||
allowedValueTypeName: BuildStepInputValueTypeName.NUMBER,
|
||||
}),
|
||||
],
|
||||
fn: async (stepCtx, { inputs, signal, env }) => {
|
||||
// The daemon needs this credential, but shell commands do not.
|
||||
@@ -49,18 +44,6 @@ export function createStartSandboxBuildFunction(ctx: CustomBuildContext): BuildF
|
||||
throw new SystemError('MCP server URL is required to start the sandbox daemon.');
|
||||
}
|
||||
const sandboxId = String(inputs.sandbox_id.value);
|
||||
const maxDurationSeconds = inputs.max_duration_seconds?.value;
|
||||
if (
|
||||
maxDurationSeconds !== undefined &&
|
||||
(typeof maxDurationSeconds !== 'number' ||
|
||||
!Number.isFinite(maxDurationSeconds) ||
|
||||
maxDurationSeconds <= 0)
|
||||
) {
|
||||
throw new UserError(
|
||||
'EAS_SANDBOX_INVALID_DURATION',
|
||||
`Invalid sandbox maximum duration: ${String(maxDurationSeconds)}. Provide a finite number greater than zero, or omit max_duration_seconds.`
|
||||
);
|
||||
}
|
||||
const daemon = await startSandboxDaemonAsync({
|
||||
credential: sandboxToken,
|
||||
serverUrl: mcpServerUrl,
|
||||
@@ -80,21 +63,7 @@ export function createStartSandboxBuildFunction(ctx: CustomBuildContext): BuildF
|
||||
stepCtx.logger.info('Sandbox daemon started.');
|
||||
|
||||
await withLogPhaseAsync(stepCtx.logger, AWAIT_SANDBOX_STEP_NAME, async () => {
|
||||
const timeoutSignal =
|
||||
maxDurationSeconds === undefined
|
||||
? undefined
|
||||
: AbortSignal.timeout(Math.ceil(maxDurationSeconds * 1000));
|
||||
await waitForCompletionAsync(
|
||||
AbortSignal.any([
|
||||
...(signal ? [signal] : []),
|
||||
...(timeoutSignal ? [timeoutSignal] : []),
|
||||
])
|
||||
);
|
||||
if (timeoutSignal?.aborted) {
|
||||
stepCtx.logger.info(
|
||||
`Sandbox reached its maximum runtime of ${maxDurationSeconds} seconds. Stopping.`
|
||||
);
|
||||
}
|
||||
await waitForCancellationAsync(signal);
|
||||
});
|
||||
} finally {
|
||||
await daemon.stopAsync();
|
||||
@@ -120,11 +89,11 @@ export async function markSandboxReadyAsync(
|
||||
}
|
||||
}
|
||||
|
||||
async function waitForCompletionAsync(signal: AbortSignal): Promise<void> {
|
||||
if (signal.aborted) {
|
||||
async function waitForCancellationAsync(signal?: AbortSignal): Promise<void> {
|
||||
if (signal?.aborted) {
|
||||
return;
|
||||
}
|
||||
await new Promise<void>(resolve => {
|
||||
signal.addEventListener('abort', () => resolve(), { once: true });
|
||||
signal?.addEventListener('abort', () => resolve(), { once: true });
|
||||
});
|
||||
}
|
||||
@@ -330,8 +330,7 @@ describe(DeviceRunSessionWorkerApi, () => {
|
||||
});
|
||||
|
||||
it('reports a request that failed before www responded', async () => {
|
||||
const reason = new Error('socket hang up');
|
||||
jest.mocked(turtleFetch).mockRejectedValueOnce(reason);
|
||||
jest.mocked(turtleFetch).mockRejectedValueOnce(new Error('socket hang up'));
|
||||
|
||||
const error = await createApi()
|
||||
.getSessionAsync()
|
||||
@@ -339,7 +338,6 @@ describe(DeviceRunSessionWorkerApi, () => {
|
||||
|
||||
expect(error).toBeInstanceOf(DeviceRunSessionWorkerApiError);
|
||||
expect(error.status).toBeUndefined();
|
||||
expect(error.cause).toBe(reason);
|
||||
expect(error.message).toContain('failed before www responded: socket hang up');
|
||||
});
|
||||
|
||||
|
||||
@@ -88,16 +88,11 @@ export class DeviceRunSessionWorkerApiError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
/** The HTTP status of the response, or undefined when no response arrived. */
|
||||
readonly status: number | undefined,
|
||||
options?: ErrorOptions
|
||||
readonly status: number | undefined
|
||||
) {
|
||||
super(message, options);
|
||||
super(message);
|
||||
this.name = 'DeviceRunSessionWorkerApiError';
|
||||
}
|
||||
|
||||
get isTransient(): boolean {
|
||||
return this.status === undefined || this.status >= 500;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,8 +218,7 @@ export class DeviceRunSessionWorkerApi {
|
||||
`${routeDescription} failed before www responded: ${
|
||||
reason instanceof Error ? reason.message : String(reason)
|
||||
}. Check the network connection of the worker.`,
|
||||
undefined,
|
||||
{ cause: reason }
|
||||
undefined
|
||||
);
|
||||
}
|
||||
const response = responseResult.value;
|
||||
|
||||
@@ -1,16 +1,4 @@
|
||||
import { CombinedError } from '@urql/core';
|
||||
|
||||
import {
|
||||
describeError,
|
||||
findErrorCode,
|
||||
findGraphqlErrorCode,
|
||||
isConnectFailure,
|
||||
isConnectionInterruptedError,
|
||||
isTransferFailure,
|
||||
isTransientGraphqlError,
|
||||
} from '../networkErrors';
|
||||
|
||||
const { FetchError } = jest.requireActual('node-fetch') as typeof import('node-fetch');
|
||||
import { isConnectFailure, isConnectionInterruptedError } from '../networkErrors';
|
||||
|
||||
it.each([
|
||||
'EAI_AGAIN',
|
||||
@@ -46,77 +34,3 @@ it.each(['ETIMEDOUT', 'CERT_HAS_EXPIRED', undefined])('does not automatically re
|
||||
expect(isConnectFailure(error)).toBe(false);
|
||||
expect(isConnectionInterruptedError(error)).toBe(false);
|
||||
});
|
||||
|
||||
it('finds the errno code on the cause of an undici fetch failure', () => {
|
||||
const error = new CombinedError({
|
||||
networkError: new TypeError('fetch failed', {
|
||||
cause: Object.assign(new Error('read ECONNRESET'), { code: 'ECONNRESET' }),
|
||||
}),
|
||||
});
|
||||
expect(findErrorCode(error)).toBe('ECONNRESET');
|
||||
expect(findErrorCode(new Error('Request failed'))).toBeUndefined();
|
||||
expect(findErrorCode('Request failed')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('finds the www error code on a GraphQL error', () => {
|
||||
const error = new CombinedError({
|
||||
graphQLErrors: [
|
||||
{ message: 'Too many requests', extensions: { errorCode: 'TOO_MANY_REQUESTS' } },
|
||||
],
|
||||
});
|
||||
expect(findGraphqlErrorCode(error)).toBe('TOO_MANY_REQUESTS');
|
||||
expect(
|
||||
findGraphqlErrorCode(new CombinedError({ graphQLErrors: ['Build not found'] }))
|
||||
).toBeUndefined();
|
||||
expect(findGraphqlErrorCode(new Error('Request failed'))).toBeUndefined();
|
||||
});
|
||||
|
||||
it.each([
|
||||
['Request failed', 'ECONNRESET', 'Request failed (ECONNRESET)'],
|
||||
['read ECONNRESET', 'ECONNRESET', 'read ECONNRESET'],
|
||||
['Request failed', undefined, 'Request failed'],
|
||||
])('describes %p with code %p as %p', (message, code, expected) => {
|
||||
expect(describeError(Object.assign(new Error(message), { code }))).toBe(expected);
|
||||
});
|
||||
|
||||
it('treats a missing response, a 5xx response or an isTransient GraphQL error as transient', () => {
|
||||
expect(
|
||||
isTransientGraphqlError(new CombinedError({ networkError: new Error('fetch failed') }))
|
||||
).toBe(true);
|
||||
expect(
|
||||
isTransientGraphqlError(
|
||||
new CombinedError({ graphQLErrors: ['Internal Server Error'], response: { status: 503 } })
|
||||
)
|
||||
).toBe(true);
|
||||
expect(
|
||||
isTransientGraphqlError(
|
||||
new CombinedError({
|
||||
graphQLErrors: [{ message: 'Database unavailable', extensions: { isTransient: true } }],
|
||||
response: { status: 200 },
|
||||
})
|
||||
)
|
||||
).toBe(true);
|
||||
expect(
|
||||
isTransientGraphqlError(
|
||||
new CombinedError({ graphQLErrors: ['Build not found'], response: { status: 200 } })
|
||||
)
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it.each([
|
||||
[
|
||||
'a node-fetch socket failure',
|
||||
new FetchError('request failed', 'system', { code: 'ECONNRESET' } as any),
|
||||
true,
|
||||
],
|
||||
['a node-fetch body size failure', new FetchError('too large', 'max-size'), false],
|
||||
['a body reset', Object.assign(new Error('aborted'), { code: 'ECONNRESET' }), true],
|
||||
[
|
||||
'a body closed early',
|
||||
Object.assign(new Error('closed'), { code: 'ERR_STREAM_PREMATURE_CLOSE' }),
|
||||
true,
|
||||
],
|
||||
['an HTTP error response', new Error('Unexpected response from server (500)'), false],
|
||||
])('classifies %s as a transfer failure or not', (_label, error, expected) => {
|
||||
expect(isTransferFailure(error)).toBe(expected);
|
||||
});
|
||||
@@ -1,5 +1,3 @@
|
||||
import { CombinedError } from '@urql/core';
|
||||
|
||||
const CONNECT_FAILURE_CODES = new Set([
|
||||
'EAI_AGAIN',
|
||||
'ECONNREFUSED',
|
||||
@@ -32,50 +30,3 @@ export function isConnectionInterruptedError(error: unknown): boolean {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Errno code of the error or its causes; undici keeps it on cause, urql on networkError. */
|
||||
export function findErrorCode(error: unknown): string | undefined {
|
||||
let current: unknown = error;
|
||||
while (current instanceof Error) {
|
||||
if ('code' in current && typeof current.code === 'string') {
|
||||
return current.code;
|
||||
}
|
||||
current = current instanceof CombinedError ? current.networkError : current.cause;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function findGraphqlErrorCode(error: unknown): string | undefined {
|
||||
if (!(error instanceof CombinedError)) {
|
||||
return undefined;
|
||||
}
|
||||
const code = error.graphQLErrors.at(0)?.extensions.errorCode;
|
||||
return typeof code === 'string' ? code : undefined;
|
||||
}
|
||||
|
||||
export function describeError(error: unknown): string {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
const code = findErrorCode(error);
|
||||
return code && !message.includes(code) ? `${message} (${code})` : message;
|
||||
}
|
||||
|
||||
export function isTransientGraphqlError(error: CombinedError): boolean {
|
||||
return (
|
||||
Boolean(error.networkError) ||
|
||||
error.response?.status >= 500 ||
|
||||
error.graphQLErrors.some(graphqlError => graphqlError.extensions.isTransient === true)
|
||||
);
|
||||
}
|
||||
|
||||
// node-fetch throws type 'system' for a socket failure before the headers; after them it forwards
|
||||
// ECONNRESET or ERR_STREAM_PREMATURE_CLOSE to the body. HTTP error responses never throw.
|
||||
export function isTransferFailure(error: unknown): boolean {
|
||||
return (
|
||||
(error instanceof Error &&
|
||||
error.name === 'FetchError' &&
|
||||
'type' in error &&
|
||||
error.type === 'system') ||
|
||||
isConnectionInterruptedError(error) ||
|
||||
findErrorCode(error) === 'ERR_STREAM_PREMATURE_CLOSE'
|
||||
);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
import { Datadog } from '../datadog';
|
||||
import { findErrorCode, findGraphqlErrorCode } from './networkErrors';
|
||||
import { promiseRetryWithCondition } from './promiseRetryWithCondition';
|
||||
|
||||
export async function retryOnNetworkFailureAsync<T>(
|
||||
attemptAsync: () => Promise<T>,
|
||||
{
|
||||
operation,
|
||||
signal,
|
||||
isRetryable,
|
||||
}: {
|
||||
operation: string;
|
||||
signal?: AbortSignal;
|
||||
isRetryable: (error: unknown) => boolean;
|
||||
}
|
||||
): Promise<T> {
|
||||
const shouldRetry = (error: unknown): boolean => !signal?.aborted && isRetryable(error);
|
||||
let attempts = 1;
|
||||
let lastError: unknown;
|
||||
const report = (outcome: 'recovered' | 'failed', error: unknown): void => {
|
||||
Datadog.log(`${operation} ${outcome} on attempt ${attempts}`, {
|
||||
event: 'network_retry',
|
||||
operation,
|
||||
outcome,
|
||||
attempts: String(attempts),
|
||||
code: findErrorCode(error) ?? findGraphqlErrorCode(error) ?? 'unknown',
|
||||
});
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await promiseRetryWithCondition(
|
||||
async () => {
|
||||
signal?.throwIfAborted();
|
||||
return await attemptAsync();
|
||||
},
|
||||
shouldRetry,
|
||||
{ retries: 5, minTimeout: 1_000, factor: 2 },
|
||||
({ attemptNumber, error }) => {
|
||||
attempts = attemptNumber;
|
||||
lastError = error;
|
||||
}
|
||||
)();
|
||||
if (attempts > 1) {
|
||||
report('recovered', lastError);
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (attempts > 1 && !signal?.aborted) {
|
||||
report('failed', error);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -252,7 +252,7 @@
|
||||
},
|
||||
"update": {
|
||||
"node": {
|
||||
"version": "22.23.4"
|
||||
"version": "22.23.3"
|
||||
},
|
||||
"s3": {
|
||||
"templates": {
|
||||
|
||||
@@ -33,7 +33,7 @@ const PROJECT_PAGES: Record<string, string> = {
|
||||
|
||||
export default class Browse extends EasCommand {
|
||||
static override description =
|
||||
'transition from the terminal to the web browser to view and interact with your project on https://expo.dev';
|
||||
'Transition from the terminal to the web browser to view and interact with your project on https://expo.dev';
|
||||
|
||||
static override args = {
|
||||
page: Args.string({
|
||||
|
||||
@@ -13,7 +13,7 @@ import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
|
||||
import { pollForBackgroundJobReceiptAsync } from '../../utils/pollForBackgroundJobReceiptAsync';
|
||||
|
||||
export default class ChannelDelete extends EasCommand {
|
||||
static override description = 'delete a channel';
|
||||
static override description = 'Delete a channel';
|
||||
|
||||
static override args = {
|
||||
name: Args.string({
|
||||
|
||||
@@ -50,7 +50,7 @@ type ChannelRolloutArgsAndFlags = {
|
||||
Partial<CreateRolloutNonInteractiveOptions>;
|
||||
|
||||
export default class ChannelRollout extends EasCommand {
|
||||
static override description = 'roll a new branch out on a channel incrementally';
|
||||
static override description = 'Roll a new branch out on a channel incrementally.';
|
||||
|
||||
static override args = {
|
||||
channel: Args.string({
|
||||
|
||||
@@ -7,7 +7,7 @@ import { SetUpBuildCredentialsCommandAction } from '../../credentials/manager/Se
|
||||
import { selectPlatformAsync } from '../../platform';
|
||||
|
||||
export default class InitializeBuildCredentials extends EasCommand {
|
||||
static override description = 'set up credentials for building your project';
|
||||
static override description = 'Set up credentials for building your project.';
|
||||
|
||||
static override flags = {
|
||||
platform: Flags.option({
|
||||
|
||||
@@ -22,7 +22,7 @@ interface DeployAliasDeleteFlags {
|
||||
}
|
||||
|
||||
export default class WorkerAliasDelete extends EasCommand {
|
||||
static override description = 'delete deployment aliases';
|
||||
static override description = 'Delete deployment aliases.';
|
||||
static override aliases = ['worker:alias:delete'];
|
||||
static override state = 'preview';
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ interface RawDeployAliasFlags {
|
||||
}
|
||||
|
||||
export default class WorkerAlias extends EasCommand {
|
||||
static override description = 'assign deployment aliases';
|
||||
static override description = 'Assign deployment aliases.';
|
||||
static override aliases = ['worker:alias', 'deploy:promote'];
|
||||
static override state = 'preview';
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ interface RawDeployDeleteFlags {
|
||||
}
|
||||
|
||||
export default class WorkerDelete extends EasCommand {
|
||||
static override description = 'delete a deployment';
|
||||
static override description = 'Delete a deployment.';
|
||||
static override aliases = ['worker:delete'];
|
||||
static override state = 'preview';
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ async function withSuppressedOutputAsync<T>(fn: () => Promise<T>): Promise<T> {
|
||||
/* eslint-enable no-console */
|
||||
|
||||
export default class Go extends EasCommand {
|
||||
static override description = 'create a custom Expo Go and submit to TestFlight';
|
||||
static override description = 'Create a custom Expo Go and submit to TestFlight';
|
||||
static override hidden = true;
|
||||
|
||||
static override flags = {
|
||||
|
||||
@@ -22,7 +22,7 @@ import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
|
||||
|
||||
export default class ObserveEvent extends EasCommand {
|
||||
static override description =
|
||||
'display a single Observe event (metric, log, or error) by its ID. IDs are included in event data when the `--json` flag is passed to `eas observe:session`, `eas observe:metrics`, or `eas observe:events`';
|
||||
'display a single Observe event (metric, log, or error) by its ID. IDs are included in event data when the `--json` flag is passed to `eas observe:session`, `eas observe:metrics`, or `eas observe:events`.';
|
||||
|
||||
static override args = {
|
||||
id: Args.string({
|
||||
|
||||
@@ -36,7 +36,7 @@ const DEFAULT_EVENTS_LIMIT = 10;
|
||||
|
||||
export default class ObserveEvents extends EasCommand {
|
||||
static override description =
|
||||
'display individual events emitted by the app via `logEvent`, filtered by the event name in the argument. With no arguments, a list of the available event names and associated event counts is returned';
|
||||
'display individual events emitted by the app via `logEvent`, filtered by the event name in the argument. With no arguments, a list of the available event names and associated event counts is returned.';
|
||||
|
||||
static override args = {
|
||||
eventName: Args.string({
|
||||
|
||||
@@ -134,7 +134,7 @@ export default class New extends EasCommand {
|
||||
static override aliases = ['new'];
|
||||
|
||||
static override description =
|
||||
'create a new project configured with Expo Application Services (EAS)';
|
||||
'Create a new project configured with Expo Application Services (EAS)';
|
||||
|
||||
static override args = {
|
||||
path: Args.string({
|
||||
|
||||
@@ -35,7 +35,7 @@ import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
|
||||
export default class SimulatorControl extends EasCommand {
|
||||
static override aliases = ['sim:control'];
|
||||
static override description =
|
||||
'[EXPERIMENTAL] run a serve-sim action on a remote iOS simulator session on EAS. Run without an action to list the actions the session supports. To save a screenshot locally, run `eas simulator:control screenshot.capture --output ./screenshot.png`';
|
||||
'[EXPERIMENTAL] run a serve-sim action on a remote iOS simulator session on EAS. Run without an action to list the actions the session supports. To save a screenshot locally, run `eas simulator:control screenshot.capture --output ./screenshot.png`.';
|
||||
static override strict = false;
|
||||
|
||||
static override examples = [
|
||||
|
||||
@@ -39,7 +39,7 @@ type DeviceRunSessionArtifact = DeviceRunSessionById['artifacts'][number];
|
||||
export default class SimulatorGet extends EasCommand {
|
||||
static override aliases = ['sim:get'];
|
||||
static override description =
|
||||
"[EXPERIMENTAL] get info about a remote simulator session on EAS by its simulator session ID. Preview links follow the session's saved sharing preference";
|
||||
"[EXPERIMENTAL] get info about a remote simulator session on EAS by its simulator session ID. Preview links follow the session's saved sharing preference.";
|
||||
|
||||
static override flags = {
|
||||
id: Flags.string({
|
||||
|
||||
@@ -83,7 +83,7 @@ export default class Simulator extends EasCommand {
|
||||
static override aliases = ['simulator:start', 'sim:start'];
|
||||
static override hiddenAliases = ['sim'];
|
||||
static override description =
|
||||
'[EXPERIMENTAL] start a remote simulator session on EAS and get instructions to connect to it. The default browser preview link requires sign-in';
|
||||
'[EXPERIMENTAL] start a remote simulator session on EAS and get instructions to connect to it. The default browser preview link requires sign-in.';
|
||||
|
||||
static override flags = {
|
||||
platform: Flags.option({
|
||||
|
||||
@@ -9,7 +9,7 @@ import { promptAsync } from '../../prompts';
|
||||
|
||||
export default class WorkflowRunCancel extends EasCommand {
|
||||
static override description =
|
||||
'cancel one or more workflow runs. If no workflow run IDs are provided, you will be prompted to select IN_PROGRESS runs to cancel';
|
||||
'Cancel one or more workflow runs. If no workflow run IDs are provided, you will be prompted to select IN_PROGRESS runs to cancel.';
|
||||
|
||||
static override strict = false;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
|
||||
export default class WorkflowList extends EasCommand {
|
||||
static override hidden = true;
|
||||
|
||||
static override description = 'list workflows for the current project';
|
||||
static override description = 'List workflows for the current project';
|
||||
|
||||
static override flags = {
|
||||
...EasJsonOnlyFlag,
|
||||
|
||||
@@ -26,7 +26,7 @@ function printLogsForAllSteps(logs: JobLogs): void {
|
||||
|
||||
export default class WorkflowLogView extends EasCommand {
|
||||
static override description =
|
||||
'view logs for a workflow run, selecting a job and step to view. You can pass in either a workflow run ID or a job ID. If no ID is passed in, you will be prompted to select from recent workflow runs for the current project';
|
||||
'view logs for a workflow run, selecting a job and step to view. You can pass in either a workflow run ID or a job ID. If no ID is passed in, you will be prompted to select from recent workflow runs for the current project.';
|
||||
|
||||
static override flags = {
|
||||
...EasJsonOnlyFlag,
|
||||
|
||||
@@ -93,7 +93,7 @@ export function resolveWorkflowRunSshInput({
|
||||
|
||||
export default class WorkflowRun extends EasCommand {
|
||||
static override description =
|
||||
'run an EAS workflow. The entire local project directory will be packaged and uploaded to EAS servers for the workflow run, unless the --ref flag is used';
|
||||
'run an EAS workflow. The entire local project directory will be packaged and uploaded to EAS servers for the workflow run, unless the --ref flag is used.';
|
||||
|
||||
static override args = {
|
||||
file: Args.string({
|
||||
|
||||
@@ -32,7 +32,7 @@ import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
|
||||
|
||||
export default class WorkflowStatus extends EasCommand {
|
||||
static override description =
|
||||
'show the status of an existing workflow run. If no run ID is provided, you will be prompted to select from recent workflow runs for the current project';
|
||||
'show the status of an existing workflow run. If no run ID is provided, you will be prompted to select from recent workflow runs for the current project.';
|
||||
|
||||
static override args = {
|
||||
WORKFLOW_RUN_ID: Args.string({
|
||||
|
||||
@@ -59,7 +59,7 @@ const processedOutputs: (job: WorkflowJobResult) => FormatFieldsItem[] = job =>
|
||||
|
||||
export default class WorkflowView extends EasCommand {
|
||||
static override description =
|
||||
'view details for a workflow run, including jobs. If no run ID is provided, you will be prompted to select from recent workflow runs for the current project';
|
||||
'view details for a workflow run, including jobs. If no run ID is provided, you will be prompted to select from recent workflow runs for the current project.';
|
||||
|
||||
static override flags = {
|
||||
...EasJsonOnlyFlag,
|
||||
|
||||
@@ -42,18 +42,3 @@ Github action builds a docker image for every PR with any change in `infra/eas-b
|
||||
### VM template
|
||||
|
||||
Github action builds a new vm template for every PR with any change in `infra/eas-build-worker-images/ios/{{ templateName }}`.
|
||||
|
||||
### Packaged startup
|
||||
|
||||
Existing services run `src/services/worker/dist/main.js`. In the worker archive,
|
||||
that path points to `bin/bootstrap.cjs`. The bootstrap loads only Node built-ins
|
||||
and starts `bin/start-worker.sh`. The shell then uses `exec` to start the normal
|
||||
worker with the original Node binary, options, and arguments.
|
||||
|
||||
Put setup that must precede worker imports or Node startup options in the shell.
|
||||
The bootstrap forwards SIGINT, SIGTERM, IPC messages, and the worker exit status.
|
||||
It remains the supervised parent process; test service shutdown on both platforms
|
||||
before deployment. A failure in the startup shell prevents the worker from
|
||||
loading. Direct execution of `packages/worker/dist/main.js` bypasses this hook.
|
||||
|
||||
Run `yarn workspace @expo/worker test:startup` for the process-level checks.
|
||||
@@ -1,53 +0,0 @@
|
||||
// This entry point must only load Node built-ins before the startup shell runs.
|
||||
const { spawn } = require('node:child_process');
|
||||
const path = require('node:path');
|
||||
|
||||
const worker = spawn(
|
||||
'/bin/bash',
|
||||
[
|
||||
path.join(__dirname, 'start-worker.sh'),
|
||||
process.execPath,
|
||||
...process.execArgv,
|
||||
path.join(__dirname, '../dist/main.js'),
|
||||
...process.argv.slice(2),
|
||||
],
|
||||
{ stdio: process.send ? ['inherit', 'inherit', 'inherit', 'ipc'] : 'inherit' }
|
||||
);
|
||||
|
||||
const signals = ['SIGINT', 'SIGTERM'];
|
||||
for (const signal of signals) {
|
||||
process.on(signal, () => worker.kill(signal));
|
||||
}
|
||||
|
||||
// Retain the readiness channel used by process managers in development.
|
||||
if (process.send) {
|
||||
worker.on('message', message => {
|
||||
if (process.connected) {
|
||||
process.send(message, () => {});
|
||||
}
|
||||
});
|
||||
process.on('message', message => {
|
||||
if (worker.connected) {
|
||||
worker.send(message, () => {});
|
||||
}
|
||||
});
|
||||
process.on('disconnect', () => {
|
||||
if (worker.connected) {
|
||||
worker.disconnect();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
worker.on('error', error => {
|
||||
process.stderr.write(`Worker startup failed: ${error.stack ?? error}\n`, () => process.exit(1));
|
||||
});
|
||||
worker.on('exit', (code, signal) => {
|
||||
if (signal) {
|
||||
for (const forwarded of signals) {
|
||||
process.removeAllListeners(forwarded);
|
||||
}
|
||||
process.kill(process.pid, signal);
|
||||
} else {
|
||||
process.exit(code ?? 1);
|
||||
}
|
||||
});
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Direct local development must not change the machine's Java installation.
|
||||
case "${ENVIRONMENT:-}" in
|
||||
development|test) exec "$@" ;;
|
||||
staging|production) ;;
|
||||
*) echo 'Worker startup requires a known ENVIRONMENT' >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
here=$(cd "$(dirname "$0")" && pwd)
|
||||
case "${NODE_OPTIONS:-}" in
|
||||
*--use-bundled-ca*|*--use-system-ca*) echo 'Conflicting Node CA options' >&2; exit 1 ;;
|
||||
esac
|
||||
[ -z "${NODE_EXTRA_CA_CERTS:-}" ] || { echo 'Extra Node CA certificates require review' >&2; exit 1; }
|
||||
|
||||
export SSL_CERT_FILE="$here/tls/ca.pem"
|
||||
export SSL_CERT_DIR="$here/tls/empty"
|
||||
export CURL_CA_BUNDLE="$SSL_CERT_FILE"
|
||||
export REQUESTS_CA_BUNDLE="$SSL_CERT_FILE"
|
||||
export NODE_OPTIONS="${NODE_OPTIONS:+$NODE_OPTIONS }--use-openssl-ca"
|
||||
[ -s "$SSL_CERT_FILE" ] && [ -d "$SSL_CERT_DIR" ]
|
||||
|
||||
case "$(uname -s)" in
|
||||
Darwin) java_root=/Library/Java/JavaVirtualMachines ;;
|
||||
Linux) java_root=/usr/lib/jvm ;;
|
||||
*) echo 'Unsupported worker OS' >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
# Only the Java blocklist update needs root. The worker keeps its original user.
|
||||
if [ "$EUID" -eq 0 ]; then
|
||||
/bin/bash "$here/tls/block-java-certificates.sh" "$java_root"
|
||||
else
|
||||
sudo -n /bin/bash "$here/tls/block-java-certificates.sh" "$java_root"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
@@ -1,57 +0,0 @@
|
||||
# Temporary eMudhra trust policy
|
||||
|
||||
The packaged startup shell applies this policy before the normal worker starts.
|
||||
It uses the included CA bundle for Node, OpenSSL clients, curl, and Requests.
|
||||
It adds the affected certificate fingerprints to Java blocklists. Only that
|
||||
Java update needs root; the worker continues as its original user.
|
||||
|
||||
No startup download or image rebuild is required. The tarball must include
|
||||
`bin/tls/empty/.gitkeep`: this directory replaces the system hashed CA directory.
|
||||
Development and test environments skip the policy. Staging and production stop
|
||||
startup if setup fails or inherited Node trust options conflict.
|
||||
|
||||
## Pinned data
|
||||
|
||||
`ca.pem` is the Mozilla CA bundle from https://curl.se/ca/cacert.pem, retrieved
|
||||
on 2026-10-22. Its header identifies the source snapshot as 2026-10-20.
|
||||
Source and bundled SHA-256:
|
||||
`796f1389bfea13c0ed78f663b765baaff54a508e5483786bd6ece73c5e3e3cbe`.
|
||||
The bundle already excludes all four affected root public keys. No certificates
|
||||
were removed from the downloaded file. Original source comments are retained.
|
||||
|
||||
`blocked-certs.txt` contains SHA-256 fingerprints for the four roots and 16
|
||||
intermediate certificates published at:
|
||||
|
||||
- https://emudhra.we-have-a-problem.com/roots.json
|
||||
- https://emudhra.we-have-a-problem.com/impacted-intermediates.json
|
||||
|
||||
The test fixtures retain those source records and the 12 published TLS chains
|
||||
from https://emudhra.we-have-a-problem.com/chains.zip. All were retrieved on
|
||||
2026-10-22. No private keys are included. Changes to these files are security
|
||||
policy changes and need review.
|
||||
|
||||
## Verification and limits
|
||||
|
||||
`yarn workspace @expo/worker test:startup` checks all 12 chains, a real local
|
||||
Node HTTPS request through the packaged entry point, setup failure, and Java
|
||||
blocklist preservation. Tests do not use real sudo or change the host JDKs.
|
||||
`test:unit` also checks trust-variable inheritance into the job environment.
|
||||
|
||||
Before deployment, run the packaged worker on every supported Linux and macOS
|
||||
image. Verify passwordless `sudo -n`, process shutdown, the worker connection,
|
||||
all installed Java versions, Ruby, curl, Python, and valid HTTPS controls.
|
||||
OpenSSL 3 is required for the offline chain tests, not for the worker startup.
|
||||
|
||||
This is a mitigation for the default worker and inherited job trust settings.
|
||||
It does not cover:
|
||||
|
||||
- The earlier worker-tarball download or host-side network requests.
|
||||
- Native macOS Keychain clients or a curl build that uses another trust backend.
|
||||
- Jobs that replace trust settings, use their own CA file, or install another JDK.
|
||||
- Separate container trust stores or JDKs outside the standard scanned directories.
|
||||
|
||||
The shared bundle can omit image-specific roots. Removing AAA and emSign roots
|
||||
can break valid services. Review these compatibility effects before rollout.
|
||||
Java file changes are tested; Java runtime rejection on each image is still
|
||||
required. A partial setup failure must discard the VM. Replace existing workers
|
||||
to apply or roll back the policy; do not remove it from a running worker.
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
here=$(cd "$(dirname "$0")" && pwd)
|
||||
java_root=$1
|
||||
[ -s "$here/blocked-certs.txt" ]
|
||||
|
||||
for security in "$java_root"/*/{lib/security,jre/lib/security,Contents/Home/lib/security,Contents/Home/jre/lib/security}; do
|
||||
[ -d "$security" ] || continue
|
||||
blocklist="$security/blocked.certs"
|
||||
case "$security" in */jre/lib/security) blocklist="$security/blacklisted.certs" ;; esac
|
||||
[ ! -f "$security/blacklisted.certs" ] || blocklist="$security/blacklisted.certs"
|
||||
if [ ! -f "$blocklist" ]; then printf 'Algorithm=SHA-256\n' > "$blocklist"; fi
|
||||
algorithm=$(sed -n 's/^[[:space:]]*Algorithm[[:space:]]*=[[:space:]]*//p' "$blocklist" | tr -d '\r')
|
||||
[ "$algorithm" = SHA-256 ] || { echo "Unsupported Java blocklist: $blocklist" >&2; exit 1; }
|
||||
[ -f "$blocklist.before-eas-tls-policy" ] || cp -p "$blocklist" "$blocklist.before-eas-tls-policy"
|
||||
[ -z "$(tail -c 1 "$blocklist")" ] || printf '\n' >> "$blocklist"
|
||||
while IFS= read -r fingerprint; do
|
||||
grep -Fxiq "$fingerprint" "$blocklist" || printf '%s\n' "$fingerprint" >> "$blocklist"
|
||||
done < "$here/blocked-certs.txt"
|
||||
echo "Updated Java blocklist: $blocklist"
|
||||
done
|
||||
@@ -1,20 +0,0 @@
|
||||
0164D7CEAE5BB909C272AF151FF44B1177AE9B47D9424B94F1D9558C30934D19
|
||||
42C4ACCD12C4F59597925E1A08A7A90102608543809308D50EC427E118BA1493
|
||||
432EC25F0D28DE9006D97BF752F17BBB2CD41F669933FCB072D9A1148D0261F3
|
||||
45A883F349AEDFD5F3A649B5498FFB121712BA8B448F3F2A91DBC5A766FCDDBE
|
||||
4B2460A466F95FD40113BCDCCA2CEB29B3B093921DE45474DA7DF48874C630B1
|
||||
579480AEA166290BD3C643589E795FC0D0E54E86505D180F1DFF99EFD3199512
|
||||
5F1DED4DD590AF74631290CF073B122A2AAC6A1FA479778A0BD43579BD832699
|
||||
62B7F9868263F72F6911FC78CEAF72C1979158B7368BF648683BB2AA39B02E72
|
||||
7485B51C0ED192878FA1D2F948FB529AE1842CC5086C4B67F7BE5B2039DE9489
|
||||
7DD78D5F4F13459A83DFF9ABBBA62EDBAF6F2D102BF257FD712F4D9F2746ED8D
|
||||
84112972B8E59D14560AE7E7119654474AAD119990CF3722BFC1E3B91615E1FD
|
||||
86A1ECBA089C4A8D3BBE2734C612BA341D813E043CF9E8A862CD5C57A36BBE6B
|
||||
98B896625C0C230ADEEC3EB2CF6AAD5001ECF9156A68644E82374CE5833BC25B
|
||||
9E39DE2881273ACC225A149C72BA3E0F51424963669AB633EE1DC7DF5DB067B4
|
||||
A496E23AC0CAB8155FC9B117B97EAE368EFCBB9041AEC8804D5A308D2D01C2D8
|
||||
CB6E15165AC802E9B3F993F16C25D41F4E81C21EBDE71AE1B012AC00BF9C7C3F
|
||||
D7A7A0FB5D7E2731D771E9484EBCDEF71D5F0C3E0A2948782BC83EE0EA699EF4
|
||||
E7568FE6E12331F4FD7DE61DA4C7559D0F8EB192A218D4741A3BA75184333838
|
||||
F2EDAAFF3D9B701FB4D14C9F285F8C0BAD90FC3BCC1FA07D47F4718EDABA34A5
|
||||
FD9D5C2DBBD4995AB69B8D50C439D9527B00529199C2FD01B2174EB58F07021F
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1 +0,0 @@
|
||||
No hashed CA files belong in this directory. It replaces the system CA lookup directory.
|
||||
@@ -11,12 +11,11 @@
|
||||
"compile": "tsc -p tsconfig.build.json",
|
||||
"prepublishOnly": "npm run build",
|
||||
"test": "yarn test:unit",
|
||||
"test:unit": "yarn test:startup && ./resources/jest --config jest.config.unit.ts",
|
||||
"test:unit": "./resources/jest --config jest.config.unit.ts",
|
||||
"test:unit:watch": "./resources/jest --config jest.config.unit.ts --watch",
|
||||
"test:integration": "./resources/jest --runInBand --config jest.config.integration.ts",
|
||||
"test:integration:watch": "./resources/jest --runInBand --config jest.config.integration.ts --watchAll",
|
||||
"typecheck": "tsc",
|
||||
"test:startup": "node --test tests/*.test.cjs"
|
||||
"typecheck": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "7.24.7",
|
||||
|
||||
@@ -120,10 +120,10 @@ fi
|
||||
|
||||
# Create backward-compatible symlink for orchestrator
|
||||
# The orchestrator expects ./src/services/worker/dist/main.js
|
||||
# Route it through the packaged startup wrapper before loading worker modules.
|
||||
# but the new structure has ./packages/worker/dist/main.js
|
||||
# We're only symlinking the specific file to discover any other legacy path usage
|
||||
mkdir -p "$target_root_dir/src/services/worker/dist"
|
||||
ln -s ../../../../packages/worker/bin/bootstrap.cjs "$target_root_dir/src/services/worker/dist/main.js"
|
||||
ln -s ../../../../packages/worker/dist/main.js "$target_root_dir/src/services/worker/dist/main.js"
|
||||
|
||||
tar zcf $OUTPUT_FILE -C $target_root_dir .
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ describe(createBuildContext.name, () => {
|
||||
buildId: 'build-id',
|
||||
buildLogger,
|
||||
addBuildLogMask: jest.fn(),
|
||||
createLogMaskingStream: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -21,10 +21,6 @@ describe(getBuildEnv.name, () => {
|
||||
EAS_BUILD_COCOAPODS_CACHE_URL: process.env.EAS_BUILD_COCOAPODS_CACHE_URL,
|
||||
NPM_CONFIG_REGISTRY: process.env.NPM_CONFIG_REGISTRY,
|
||||
NODE_OPTIONS: process.env.NODE_OPTIONS,
|
||||
SSL_CERT_FILE: process.env.SSL_CERT_FILE,
|
||||
SSL_CERT_DIR: process.env.SSL_CERT_DIR,
|
||||
CURL_CA_BUNDLE: process.env.CURL_CA_BUNDLE,
|
||||
REQUESTS_CA_BUNDLE: process.env.REQUESTS_CA_BUNDLE,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -55,10 +51,6 @@ describe(getBuildEnv.name, () => {
|
||||
restoreEnv('EAS_BUILD_COCOAPODS_CACHE_URL', originalCacheUrls.EAS_BUILD_COCOAPODS_CACHE_URL);
|
||||
restoreEnv('NPM_CONFIG_REGISTRY', originalCacheUrls.NPM_CONFIG_REGISTRY);
|
||||
restoreEnv('NODE_OPTIONS', originalCacheUrls.NODE_OPTIONS);
|
||||
restoreEnv('SSL_CERT_FILE', originalCacheUrls.SSL_CERT_FILE);
|
||||
restoreEnv('SSL_CERT_DIR', originalCacheUrls.SSL_CERT_DIR);
|
||||
restoreEnv('CURL_CA_BUNDLE', originalCacheUrls.CURL_CA_BUNDLE);
|
||||
restoreEnv('REQUESTS_CA_BUNDLE', originalCacheUrls.REQUESTS_CA_BUNDLE);
|
||||
mockProcessPlatform(originalPlatform);
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
@@ -339,15 +331,8 @@ describe(getBuildEnv.name, () => {
|
||||
expect(getNodeMemoryOptions()).toBeUndefined();
|
||||
});
|
||||
|
||||
it('keeps worker trust settings and inherited Node.js options', () => {
|
||||
process.env.NODE_OPTIONS = '--max-old-space-size=2048 --enable-source-maps --use-openssl-ca';
|
||||
const trust = {
|
||||
SSL_CERT_FILE: '/worker/bin/tls/ca.pem',
|
||||
SSL_CERT_DIR: '/worker/bin/tls/empty',
|
||||
CURL_CA_BUNDLE: '/worker/bin/tls/ca.pem',
|
||||
REQUESTS_CA_BUNDLE: '/worker/bin/tls/ca.pem',
|
||||
};
|
||||
Object.assign(process.env, trust);
|
||||
it('keeps Node.js options inherited from the worker environment in override position', () => {
|
||||
process.env.NODE_OPTIONS = '--max-old-space-size=2048 --enable-source-maps';
|
||||
jest.spyOn(process, 'constrainedMemory').mockReturnValue(6 * 1024 ** 3);
|
||||
jest.spyOn(v8, 'getHeapStatistics').mockReturnValue({
|
||||
heap_size_limit: 2 * 1024 ** 3,
|
||||
@@ -372,9 +357,8 @@ describe(getBuildEnv.name, () => {
|
||||
});
|
||||
|
||||
expect(env.NODE_OPTIONS).toBe(
|
||||
'--max-old-space-size=3072 --max-old-space-size=2048 --enable-source-maps --use-openssl-ca'
|
||||
'--max-old-space-size=3072 --max-old-space-size=2048 --enable-source-maps'
|
||||
);
|
||||
expect(env).toEqual(expect.objectContaining(trust));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { TransformCallback, Writable } from 'node:stream';
|
||||
import { Readable, Transform, TransformCallback, Writable } from 'node:stream';
|
||||
import { pipeline } from 'node:stream/promises';
|
||||
import { EnvironmentSecretType } from '@expo/eas-build-job';
|
||||
import z from 'zod';
|
||||
|
||||
@@ -356,3 +357,99 @@ describe('logger', () => {
|
||||
expect(outputStream.readableLength).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createLogMaskingStream', () => {
|
||||
async function maskAsync(stream: Transform, chunks: Buffer[]): Promise<Buffer> {
|
||||
const output: Buffer[] = [];
|
||||
await pipeline(
|
||||
Readable.from(chunks),
|
||||
stream,
|
||||
new Writable({
|
||||
write(chunk: Buffer, _encoding: BufferEncoding, callback: (error?: Error | null) => void) {
|
||||
output.push(chunk);
|
||||
callback();
|
||||
},
|
||||
})
|
||||
);
|
||||
return Buffer.concat(output);
|
||||
}
|
||||
|
||||
it('masks secrets, secrets as Xcode prints them in build settings, and decoded secrets', async () => {
|
||||
const { createLogMaskingStream } = await createBuildLoggerWithSecretsFilter({
|
||||
environmentSecrets: [
|
||||
{ name: 'API_KEY', value: 'ab cd=ef$gh', type: EnvironmentSecretType.STRING },
|
||||
{
|
||||
name: 'ANOTHER_SECRET_BASE64',
|
||||
value: 'YW5vdGhlclNlY3JldA==',
|
||||
type: EnvironmentSecretType.STRING,
|
||||
},
|
||||
],
|
||||
});
|
||||
const log = [
|
||||
' export API_KEY\\=ab\\ cd\\=ef\\$gh',
|
||||
'token is ab cd=ef$gh',
|
||||
'decoded anotherSecret here',
|
||||
'',
|
||||
].join('\n');
|
||||
|
||||
const masked = await maskAsync(createLogMaskingStream(), [Buffer.from(log)]);
|
||||
|
||||
expect(masked.toString()).toBe(
|
||||
[
|
||||
` export API_KEY\\=${'*'.repeat(14)}`,
|
||||
`token is ${'*'.repeat(11)}`,
|
||||
`decoded ${'*'.repeat(13)} here`,
|
||||
'',
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
it('masks secrets split across chunks, including masks added after the logger was created', async () => {
|
||||
const { createLogMaskingStream, addBuildLogMask } = await createBuildLoggerWithSecretsFilter(
|
||||
{}
|
||||
);
|
||||
addBuildLogMask('leased-token');
|
||||
|
||||
const masked = await maskAsync(createLogMaskingStream(), [
|
||||
Buffer.from('first line leased-'),
|
||||
Buffer.from('token\nsecond '),
|
||||
Buffer.from('leased-token without a newline'),
|
||||
]);
|
||||
|
||||
expect(masked.toString()).toBe(
|
||||
`first line ${'*'.repeat(12)}\nsecond ${'*'.repeat(12)} without a newline`
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps everything except secrets byte for byte, including multibyte and invalid UTF-8', async () => {
|
||||
const { createLogMaskingStream } = await createBuildLoggerWithSecretsFilter({
|
||||
environmentSecrets: [
|
||||
{ name: 'PASSWORD', value: 'pässwörd', type: EnvironmentSecretType.STRING },
|
||||
],
|
||||
});
|
||||
const log = Buffer.concat([
|
||||
Buffer.from('✓ Compiling café.swift\r\n'),
|
||||
Buffer.from([0xff, 0xfe, 0x0a]),
|
||||
Buffer.from('password: pässwörd\n'),
|
||||
]);
|
||||
// Split inside the multibyte characters.
|
||||
const chunks = [
|
||||
log.subarray(0, 1),
|
||||
log.subarray(1, 20),
|
||||
log.subarray(20, 40),
|
||||
log.subarray(40),
|
||||
];
|
||||
|
||||
const masked = await maskAsync(createLogMaskingStream(), chunks);
|
||||
|
||||
const passwordBytes = Buffer.byteLength('pässwörd');
|
||||
expect(masked).toEqual(
|
||||
Buffer.concat([
|
||||
Buffer.from('✓ Compiling café.swift\r\n'),
|
||||
Buffer.from([0xff, 0xfe, 0x0a]),
|
||||
Buffer.from(`password: ${'*'.repeat(passwordBytes)}\n`),
|
||||
])
|
||||
);
|
||||
expect(masked.length).toBe(log.length);
|
||||
});
|
||||
});
|
||||
@@ -115,6 +115,7 @@ describe('BuildService Datadog setup', () => {
|
||||
createBuildLoggerWithSecretsFilterMock.mockResolvedValue({
|
||||
logger: buildLogger,
|
||||
addBuildLogMask: jest.fn(),
|
||||
createLogMaskingStream: jest.fn(),
|
||||
cleanUp: jest.fn(async () => {}),
|
||||
logBuffer: { getLogs: () => [], getPhaseLogs: () => [] } as any,
|
||||
outputStream: {} as any,
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import { RemoteLoggerStream, uploadWithSignedUrl } from '@expo/build-tools';
|
||||
import fs from 'fs-extra';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import { Readable } from 'stream';
|
||||
import zlib from 'zlib';
|
||||
|
||||
import config from '../config';
|
||||
import { uploadXcodeBuildLogs } from '../ios/xcodeLogs';
|
||||
import { createTextMaskingStream } from '../logger';
|
||||
|
||||
// These tests use real fs and directories in os.tmpdir(), since memfs read streams can't be closed.
|
||||
jest.unmock('fs');
|
||||
jest.unmock('node:fs');
|
||||
|
||||
const logger = { warn: jest.fn() } as any;
|
||||
|
||||
async function readAllAsync(stream: Readable): Promise<Buffer> {
|
||||
const chunks: Buffer[] = [];
|
||||
for await (const chunk of stream) {
|
||||
chunks.push(Buffer.from(chunk));
|
||||
}
|
||||
return Buffer.concat(chunks);
|
||||
}
|
||||
|
||||
describe(uploadXcodeBuildLogs, () => {
|
||||
const originalGcs = { ...config.loggers.gcs };
|
||||
let tmpDir: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'xcode-logs-test-'));
|
||||
config.loggers.gcs.signedUploadUrlForXcodeBuildLogs = {
|
||||
url: 'https://gcs.expo.test/xcode-logs',
|
||||
headers: {},
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
Object.assign(config.loggers.gcs, originalGcs);
|
||||
jest.mocked(uploadWithSignedUrl).mockReset();
|
||||
await fs.remove(tmpDir);
|
||||
});
|
||||
|
||||
it.each([
|
||||
['no compression', null, (body: Buffer) => body],
|
||||
['gzip', RemoteLoggerStream.CompressionMethod.GZIP, zlib.gunzipSync],
|
||||
['brotli', RemoteLoggerStream.CompressionMethod.BR, zlib.brotliDecompressSync],
|
||||
])('uploads the log with secrets masked (%s)', async (_name, compressionMethod, decompress) => {
|
||||
config.loggers.gcs.compressionMethod = compressionMethod as any;
|
||||
const logsPath = path.join(tmpDir, 'xcodebuild.log');
|
||||
await fs.writeFile(logsPath, ' export API_KEY\\=ab\\ cd\\=ef\\$gh\n** BUILD SUCCEEDED **\n');
|
||||
let uploaded: Buffer | undefined;
|
||||
jest.mocked(uploadWithSignedUrl).mockImplementation(async ({ srcGeneratorAsync }) => {
|
||||
uploaded = await readAllAsync((await srcGeneratorAsync()) as Readable);
|
||||
return 'https://gcs.expo.test/xcode-logs';
|
||||
});
|
||||
|
||||
await uploadXcodeBuildLogs(logger, logsPath, () =>
|
||||
createTextMaskingStream(new Set(['ab cd=ef$gh']))
|
||||
);
|
||||
|
||||
expect(decompress(uploaded!).toString()).toBe(
|
||||
` export API_KEY\\=${'*'.repeat(14)}\n** BUILD SUCCEEDED **\n`
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
['no compression', null],
|
||||
['gzip', RemoteLoggerStream.CompressionMethod.GZIP],
|
||||
])('fails the upload when the log cannot be read (%s)', async (_name, compressionMethod) => {
|
||||
config.loggers.gcs.compressionMethod = compressionMethod as any;
|
||||
jest.mocked(uploadWithSignedUrl).mockImplementation(async ({ srcGeneratorAsync }) => {
|
||||
await readAllAsync((await srcGeneratorAsync()) as Readable);
|
||||
return 'https://gcs.expo.test/xcode-logs';
|
||||
});
|
||||
|
||||
// A directory can be stat'ed but not read.
|
||||
await expect(
|
||||
uploadXcodeBuildLogs(logger, tmpDir, () => createTextMaskingStream(new Set(['secret'])))
|
||||
).rejects.toThrow('EISDIR');
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,7 @@ import { BuildContext, BuildContextOptions, LogBuffer, RuntimeSettings } from '@
|
||||
import { Job, ManagedArtifactType, Metadata, Platform } from '@expo/eas-build-job';
|
||||
import { bunyan } from '@expo/logger';
|
||||
import assert from 'assert';
|
||||
import { Transform } from 'stream';
|
||||
|
||||
import { GCSCacheManager } from './CacheManager';
|
||||
import config from './config';
|
||||
@@ -27,6 +28,7 @@ export async function createBuildContext<TJob extends Job>({
|
||||
buildId,
|
||||
buildLogger,
|
||||
addBuildLogMask,
|
||||
createLogMaskingStream,
|
||||
}: {
|
||||
job: TJob;
|
||||
logBuffer: LogBuffer;
|
||||
@@ -36,6 +38,7 @@ export async function createBuildContext<TJob extends Job>({
|
||||
buildId: string;
|
||||
buildLogger: bunyan;
|
||||
addBuildLogMask: (secret: string) => void;
|
||||
createLogMaskingStream: () => Transform;
|
||||
}): Promise<BuildContext<TJob>> {
|
||||
const childLogger = buildLogger.child({ buildId });
|
||||
await RuntimeSettings.loadAsync({
|
||||
@@ -51,7 +54,7 @@ export async function createBuildContext<TJob extends Job>({
|
||||
switch (type) {
|
||||
case ManagedArtifactType.XCODE_BUILD_LOGS: {
|
||||
if (job.platform === Platform.IOS) {
|
||||
await uploadXcodeBuildLogs(logger, paths[0]);
|
||||
await uploadXcodeBuildLogs(logger, paths[0], createLogMaskingStream);
|
||||
return { filename: null };
|
||||
}
|
||||
throw new Error('Uploading Xcode logs in non-iOS builds is not supported');
|
||||
|
||||
@@ -3,14 +3,18 @@ import { bunyan } from '@expo/logger';
|
||||
import fs from 'fs-extra';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import { Readable, pipeline } from 'stream';
|
||||
import { Readable, Transform, pipeline } from 'stream';
|
||||
import { promisify } from 'util';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import zlib from 'zlib';
|
||||
|
||||
import config from '../config';
|
||||
|
||||
export async function uploadXcodeBuildLogs(logger: bunyan, logsPath: string): Promise<void> {
|
||||
export async function uploadXcodeBuildLogs(
|
||||
logger: bunyan,
|
||||
logsPath: string,
|
||||
createLogMaskingStream: () => Transform
|
||||
): Promise<void> {
|
||||
if (!config.loggers.gcs.signedUploadUrlForXcodeBuildLogs) {
|
||||
logger.warn('GCS Presigned URL for Xcode logs was not specified, skipping upload');
|
||||
} else {
|
||||
@@ -18,8 +22,15 @@ export async function uploadXcodeBuildLogs(logger: bunyan, logsPath: string): Pr
|
||||
signedUrl: config.loggers.gcs.signedUploadUrlForXcodeBuildLogs,
|
||||
srcGeneratorAsync: async () => {
|
||||
const stat = await fs.stat(logsPath);
|
||||
// Masking replaces each byte of a secret with one byte, so the size stays the same.
|
||||
// pipeline passes read errors on to the masked stream, which fails the upload.
|
||||
const maskedStream = pipeline(
|
||||
fs.createReadStream(logsPath),
|
||||
createLogMaskingStream(),
|
||||
() => {}
|
||||
);
|
||||
const { stream } = await compress(
|
||||
{ stream: fs.createReadStream(logsPath), length: stat.size },
|
||||
{ stream: maskedStream, length: stat.size },
|
||||
config.loggers.gcs.compressionMethod
|
||||
);
|
||||
return stream;
|
||||
|
||||
@@ -102,6 +102,40 @@ function createTransformStream(secretPatterns: ReadonlySet<string>): Transform {
|
||||
});
|
||||
}
|
||||
|
||||
// Characters that Xcode escapes with a backslash when it prints build settings.
|
||||
const XCODE_ESCAPED_CHARACTERS = /[\t !"#$&'()*;<=>?[\\\]^`{|}~]/g;
|
||||
|
||||
/**
|
||||
* Masks secrets in a text file's contents, line by line, including secrets written the way Xcode
|
||||
* prints build settings. Masking works on bytes, so everything else stays unchanged.
|
||||
*/
|
||||
export function createTextMaskingStream(secretPatterns: ReadonlySet<string>): Transform {
|
||||
const patterns = [
|
||||
...new Set(
|
||||
[...secretPatterns].flatMap(secret => [
|
||||
secret,
|
||||
secret.replace(XCODE_ESCAPED_CHARACTERS, '\\$&'),
|
||||
])
|
||||
),
|
||||
].map(pattern => Buffer.from(pattern).toString('latin1'));
|
||||
const maskLine = (line: string): string =>
|
||||
patterns.some(pattern => line.includes(pattern)) ? maskSecrets(line, patterns) : line;
|
||||
let partialLine = '';
|
||||
return new Transform({
|
||||
transform(chunk: Buffer, _encoding: BufferEncoding, callback: TransformCallback) {
|
||||
const lines = (partialLine + chunk.toString('latin1')).split('\n');
|
||||
partialLine = lines.pop() ?? '';
|
||||
callback(
|
||||
null,
|
||||
lines.length > 0 ? Buffer.from(`${lines.map(maskLine).join('\n')}\n`, 'latin1') : undefined
|
||||
);
|
||||
},
|
||||
flush(callback: TransformCallback) {
|
||||
callback(null, partialLine ? Buffer.from(maskLine(partialLine), 'latin1') : undefined);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function maskSecrets(message: string, secrets: Iterable<string>): string {
|
||||
const characters = message.split('');
|
||||
for (const secret of secrets) {
|
||||
@@ -170,6 +204,7 @@ function createDiscardStream(): Writable {
|
||||
export async function createBuildLoggerWithSecretsFilter(secrets: Job['secrets']): Promise<{
|
||||
logger: bunyan;
|
||||
addBuildLogMask: (secret: string) => void;
|
||||
createLogMaskingStream: () => Transform;
|
||||
cleanUp: () => Promise<void>;
|
||||
logBuffer: WorkerLogBuffer;
|
||||
outputStream: Readable;
|
||||
@@ -239,6 +274,8 @@ export async function createBuildLoggerWithSecretsFilter(secrets: Job['secrets']
|
||||
return {
|
||||
logger: buildLogger,
|
||||
addBuildLogMask,
|
||||
// Reads the masks when the stream is created, so it includes masks added during the job.
|
||||
createLogMaskingStream: () => createTextMaskingStream(secretPatterns),
|
||||
cleanUp: async () => {
|
||||
await Promise.all([remoteLoggerStream?.cleanUp?.(), httpLogStream?.cleanUp?.()]);
|
||||
},
|
||||
|
||||
@@ -275,6 +275,7 @@ export default class BuildService {
|
||||
const {
|
||||
logger: buildLogger,
|
||||
addBuildLogMask,
|
||||
createLogMaskingStream,
|
||||
cleanUp,
|
||||
logBuffer,
|
||||
} = await createBuildLoggerWithSecretsFilter(job.secrets ?? {});
|
||||
@@ -315,6 +316,7 @@ export default class BuildService {
|
||||
buildId: this.buildId,
|
||||
buildLogger,
|
||||
addBuildLogMask,
|
||||
createLogMaskingStream,
|
||||
});
|
||||
this.buildContext = ctx;
|
||||
|
||||
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICQDCCAcagAwIBAgIUU3mgjls/8ZJ8upmukdlSQR1IF/UwCgYIKoZIzj0EAwIw
|
||||
PzELMAkGA1UEBhMCTkwxEzARBgNVBAoMCmVNdWRocmEgQlYxGzAZBgNVBAMMEkVN
|
||||
IERWIFRMUyBDQSAtIEczQjAeFw0yNjEwMjAwMjIyNDFaFw0yNzA1MDMwMjI3NDFa
|
||||
MDMxMTAvBgNVBAMMKGR2LWczYi1hYWEtZW11ZGhyYS53ZS1oYXZlLWEtcHJvYmxl
|
||||
bS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATK3sfcOxxtM2Vdq9Qbw/GR
|
||||
NsHlJcnqINEInXO3fkWhw/FYT80hkqGk0jSN/EKib3YZJsr5GyfkYcpEiA2rwMgm
|
||||
o4GrMIGoMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
||||
CCsGAQUFBwMBMDMGA1UdEQQsMCqCKGR2LWczYi1hYWEtZW11ZGhyYS53ZS1oYXZl
|
||||
LWEtcHJvYmxlbS5jb20wHQYDVR0OBBYEFDggfJFz1eeToKmzFBSYkMCvpAu0MB8G
|
||||
A1UdIwQYMBaAFOIeL+ccGTkOVUtiwSAkVzUkiiUUMAoGCCqGSM49BAMCA2gAMGUC
|
||||
MDqDDOt7K313QIH0rhn/ZKnzFu8+/9W8OlTuFtDfVCTRDfRmqdyfsCfLsEk7xqHq
|
||||
uQIxAJqyLERABmU98U46OCuT5bp5h0ytuSEIGM7orTpKci5S1u1B/AOmwv162U7R
|
||||
TcVPHA==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDzjCCAragAwIBAgIRAKAk/fS6Zlx4XOSgIEg4WLcwDQYJKoZIhvcNAQELBQAw
|
||||
ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
|
||||
BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNTA1MTQwMDAwMDBaFw0y
|
||||
ODEyMzEyMzU5NTlaMD8xCzAJBgNVBAYTAk5MMRMwEQYDVQQKDAplTXVkaHJhIEJW
|
||||
MRswGQYDVQQDDBJFTSBEViBUTFMgQ0EgLSBHM0IwdjAQBgcqhkjOPQIBBgUrgQQA
|
||||
IgNiAATnntnASpdzxHNeUREdqFrCvV5kqzdLgOEsvCA47B5PDjuBL8mFnh5nr7BO
|
||||
L4vJf3SFumWqkR7opORbYtXMA9Vr5nizw4y03JN8okYOI4RTyJKTXSnUT5HhVga2
|
||||
PM7atGijggE1MIIBMTAfBgNVHSMEGDAWgBSgEQojPpbxB+zirynvgqV/0DCktDAd
|
||||
BgNVHQ4EFgQU4h4v5xwZOQ5VS2LBICRXNSSKJRQwDgYDVR0PAQH/BAQDAgEGMBIG
|
||||
A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
|
||||
MDEGA1UdIAQqMCgwCAYGZ4EMAQIBMA0GCysGAQQBg44hAQABMA0GCysGAQQBg44h
|
||||
AQJkMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FB
|
||||
QUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEF
|
||||
BQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUAA4IB
|
||||
AQBzQ1IoqpdotM6gFrR4Q3YrKifOLeaj5XXunldpVE/vZn2TxC2y0s8oYiLR5ICE
|
||||
wqVXSB7N6BM1Mp+Nif7Jbhb2IswAfSR4Iik8+B0iRmi7lYoNlycCgHjmsjOmZaxM
|
||||
QkPmjXAJbG5f4V41OsvJZmS7lI3r0IuvEDVX3GAZ13on6IImSs9ybNpHQ7NCqkMQ
|
||||
7wH4uAO1dtpFycgJSdHaCOhHjrox2BTYGLdpUrYwY3EOAjlZ8UGgsxs7mG+xquMl
|
||||
bN1LFURwfnkVMP3T/DBIZ/ys2+lNFyxK3FlArrV4/000uTnVB1lO8oGORYdXoT5V
|
||||
GUyRCEIDhF5TBUuKF4E3kf1h
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,56 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICOTCCAb6gAwIBAgIUY1R/PHrtXShV0uhLJ5EyjsHvMi0wCgYIKoZIzj0EAwIw
|
||||
PzELMAkGA1UEBhMCTkwxEzARBgNVBAoMCmVNdWRocmEgQlYxGzAZBgNVBAMMEkVN
|
||||
IERWIFRMUyBDQSAtIEczQjAeFw0yNjEwMjAwMDU5MzZaFw0yNzA1MDMwMTA0MzZa
|
||||
MC8xLTArBgNVBAMMJGR2LWczYi1lbXVkaHJhLndlLWhhdmUtYS1wcm9ibGVtLmNv
|
||||
bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFpE24ACBFHQLzpg+7D767thJ3+Q
|
||||
NIoJJugUMT/OftEz6G6uDdxlS+9VfXYBDglHjJirjEPFNglOGJoQNQuiz7Gjgacw
|
||||
gaQwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYB
|
||||
BQUHAwEwLwYDVR0RBCgwJoIkZHYtZzNiLWVtdWRocmEud2UtaGF2ZS1hLXByb2Js
|
||||
ZW0uY29tMB0GA1UdDgQWBBT4r5v4etYNuG21BqBqs273OkcHiDAfBgNVHSMEGDAW
|
||||
gBTiHi/nHBk5DlVLYsEgJFc1JIolFDAKBggqhkjOPQQDAgNpADBmAjEAlxNF+/8l
|
||||
APpgibawACy15yn5bcvTksz2Zw0R9z9nUK9e3MSSk+hXagg7LVb7V4NtAjEA4qyR
|
||||
laFPkaokrnTjqQieq8CgDQ6tIz3FjBvj3D7vkhKXHaml6zD2zT5ih2Y+lD2h
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDaDCCAu6gAwIBAgIQAKSu5njyM2K0wORgt3LyFDAKBggqhkjOPQQDAzBWMQsw
|
||||
CQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl
|
||||
ZDEgMB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwHhcNMjUwNDMwMTU1
|
||||
NDA4WhcNNDAwNDI4MTgzMDAwWjA/MQswCQYDVQQGEwJOTDETMBEGA1UECgwKZU11
|
||||
ZGhyYSBCVjEbMBkGA1UEAwwSRU0gRFYgVExTIENBIC0gRzNCMHYwEAYHKoZIzj0C
|
||||
AQYFK4EEACIDYgAE557ZwEqXc8RzXlERHahawr1eZKs3S4DhLLwgOOweTw47gS/J
|
||||
hZ4eZ6+wTi+LyX90hbplqpEe6KTkW2LVzAPVa+Z4s8OMtNyTfKJGDiOEU8iSk10p
|
||||
1E+R4VYGtjzO2rRoo4IBljCCAZIwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L
|
||||
WUIgkFQwHQYDVR0OBBYEFOIeL+ccGTkOVUtiwSAkVzUkiiUUMB0GA1UdJQQWMBQG
|
||||
CCsGAQUFBwMBBggrBgEFBQcDAjBdBgNVHSAEVjBUMDkGCysGAQQBg44hAQABMCow
|
||||
KAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB
|
||||
BAGDjiEBAmQwCAYGZ4EMAQIBMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY
|
||||
aHR0cDovL29jc3AtYi5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw
|
||||
b3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNRFZUTFNDQUczQi5wN2MwNwYDVR0f
|
||||
BDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j
|
||||
cmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E
|
||||
AwMDaAAwZQIwLmsGXi6oFMJ2klkcEMXMug6gvxQWZWkewiDWVzQyl2L6z6DuQfPO
|
||||
Ibh1grvdULDCAjEAxZvLlxUavG69J6wnSjC8XBbqNIQsJ6CE2QdNOe84Ptxb6VG8
|
||||
gt2TlfJbHii+KNvK
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdDCCAvmgAwIBAgIQAJYaPvsTWVdu0EAFtGhKWzAKBggqhkjOPQQDAzBrMQsw
|
||||
CQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhy
|
||||
YSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290
|
||||
IENBIC0gRzMwHhcNMjQwNzExMTU0MzM2WhcNMzkwNzA5MTgzMDAwWjBWMQswCQYD
|
||||
VQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg
|
||||
MB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwdjAQBgcqhkjOPQIBBgUr
|
||||
gQQAIgNiAARfD9w/q1cWxL6D9bMGH6CQ4u+gAV6GN9s+PwQx9Bl4hC+0iU8QOk8m
|
||||
WO/RwXQy10DCSxT8vSIJClHKp+Ao4qJKdYeV0SwZ7LMQziyLfxIUOY6Grja/sQFw
|
||||
LKYf8EdDXAyjggF1MIIBcTAfBgNVHSMEGDAWgBR8XQKEE9TMipuBzhccLikenEhj
|
||||
QjAdBgNVHQ4EFgQU4TqrIXzx401UrtRyt/2LWUIgkFQwHQYDVR0lBBYwFAYIKwYB
|
||||
BQUHAwEGCCsGAQUFBwMCMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIB
|
||||
FhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMHgGCCsGAQUFBwEBBGwwajAi
|
||||
BggrBgEFBQcwAYYWaHR0cDovL29jc3AuZW1zaWduLmNvbTBEBggrBgEFBQcwAoY4
|
||||
aHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbS9jZXJ0cy9lbVNpZ25FQ0NSb290
|
||||
Q0FHMy5jcnQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbXNpZ24uY29t
|
||||
P1Jvb3RDQUczLmNybDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIB
|
||||
ATAKBggqhkjOPQQDAwNpADBmAjEAt9CIpRGp46QHQYDUBnLKw+vvK0/h9vmilEAg
|
||||
TroUl/anH4x2rXHqiCtBTBfgKDegAjEA8WpG1LTZdAIL0FSYqxXeREaeTSxEofM0
|
||||
1jJH3jGvCXC79LU9UPJ2o3TU+UIj2gMV
|
||||
-----END CERTIFICATE-----
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICQjCCAcegAwIBAgIUMH3z62Z6agEULBZqrfhpw9/ZpCAwCgYIKoZIzj0EAwIw
|
||||
QDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC2VNdWRocmEgSW5jMRswGQYDVQQDDBJF
|
||||
TSBEViBUTFMgQ0EgLSBHM0MwHhcNMjYxMDIwMDIyMjQxWhcNMjcwNTAzMDIyNzQx
|
||||
WjAzMTEwLwYDVQQDDChkdi1nM2MtYWFhLWVtdWRocmEud2UtaGF2ZS1hLXByb2Js
|
||||
ZW0uY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAMPpHsQqEqIerrj/durO
|
||||
EN7gkUVJSVgIPN6+VJ2sEGXDyqXAN1fnNzGuASP/4WEr0RIhht3cYvuUYp2SYofr
|
||||
w6OBqzCBqDAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAK
|
||||
BggrBgEFBQcDATAzBgNVHREELDAqgihkdi1nM2MtYWFhLWVtdWRocmEud2UtaGF2
|
||||
ZS1hLXByb2JsZW0uY29tMB0GA1UdDgQWBBT8CNQz4OLVnIwrQYZBF+++9jTCvzAf
|
||||
BgNVHSMEGDAWgBSufhBcPCmWwahHJwVZ8eA91OUK8zAKBggqhkjOPQQDAgNpADBm
|
||||
AjEAp3ZLdfBvKcZxgR2p8LZaxWzP6uB7zU/EZ9BA49Ds2P5ByYkRodwK5qcwt4J/
|
||||
VL/vAjEAnnxrcrDX7SzoJxuho604GBh6eyBLJLCdmcy+qb+LA3u5oxP/OjAzCA4x
|
||||
v1kw6Tm4
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDzzCCAregAwIBAgIRAJHzR/Glt9OZYrleDuTimdEwDQYJKoZIhvcNAQELBQAw
|
||||
ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
|
||||
BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNTA1MTQwMDAwMDBaFw0y
|
||||
ODEyMzEyMzU5NTlaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVkaHJhIElu
|
||||
YzEbMBkGA1UEAwwSRU0gRFYgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0CAQYFK4EE
|
||||
ACIDYgAEOnp4YsjETTJN3WkDOmeCwO/u/kBV5ooSP6A3G6O9kZRRTuFypDPjYw8C
|
||||
vRiAN9nlFJ+bd9uUooHfmHsv6oiLdL3+j9pMEJnubKGVZv4+8OX2sJpVbMyLpQVh
|
||||
3xsqRB0Bo4IBNTCCATEwHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQw
|
||||
HQYDVR0OBBYEFK5+EFw8KZbBqEcnBVnx4D3U5QrzMA4GA1UdDwEB/wQEAwIBBjAS
|
||||
BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
|
||||
AjAxBgNVHSAEKjAoMAgGBmeBDAECATANBgsrBgEEAYOOIQEAATANBgsrBgEEAYOO
|
||||
IQECZDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9B
|
||||
QUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA0BggrBgEFBQcBAQQoMCYwJAYIKwYB
|
||||
BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQsFAAOC
|
||||
AQEAr7b6Mx11TIJgVzHt6EH5qGNWeiiqoMrp8E5/k8s+jvupx1n083pZ5XOzUzND
|
||||
wEUe0W4C4FIGUHNQ4XDwqOw0yK42xqm2dvCKgsko2UvDlT0haZVtTCeWMQOe5J/J
|
||||
ziaMfZwsZNfZ3aaI6XPtWDZtwY8AaNfyaeCpbtm5GcGnyNWk4jSNpbtpo6NjfXuP
|
||||
CFOm3rTjJ4zytP7Tso6iMm0L01cYFOlTmoPv4515R2r3SPnKDtijoB/D/vgxzojv
|
||||
DafgyG9afX8+laO9NbMMz4sqC1vZx3984i/sBNFiugm3Vvdq5OdJRjuGC1QILIs6
|
||||
dg/K3i8VQqRpbfaM9kIlMzZ3dQ==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,56 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICODCCAb+gAwIBAgIUbWvtwSNK/Qro223vAqyz323+VBAwCgYIKoZIzj0EAwIw
|
||||
QDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC2VNdWRocmEgSW5jMRswGQYDVQQDDBJF
|
||||
TSBEViBUTFMgQ0EgLSBHM0MwHhcNMjYxMDIwMDA1OTM2WhcNMjcwNTAzMDEwNDM2
|
||||
WjAvMS0wKwYDVQQDDCRkdi1nM2MtZW11ZGhyYS53ZS1oYXZlLWEtcHJvYmxlbS5j
|
||||
b20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAScdBQpNUOOCcag6YEVFccNRSFe
|
||||
UIl02iH53vDfoWPJFS005WzqF3CPDclB/kygP2gWF4pg/r5gPYdnI3/6Vdzro4Gn
|
||||
MIGkMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsG
|
||||
AQUFBwMBMC8GA1UdEQQoMCaCJGR2LWczYy1lbXVkaHJhLndlLWhhdmUtYS1wcm9i
|
||||
bGVtLmNvbTAdBgNVHQ4EFgQUBj2yGO/TzDOE/u/6QeUvcW8y1iMwHwYDVR0jBBgw
|
||||
FoAUrn4QXDwplsGoRycFWfHgPdTlCvMwCgYIKoZIzj0EAwIDZwAwZAIwBQOOQqG9
|
||||
ccdzM/7XIlXLtota1esALaLmgEN/ZweosBIvk4xabHcERZInWVIwO45NAjBos8Ue
|
||||
NwDe1X3ahdK2lkxqBEoBMtUHJN18TnJKs2nK1gmXpMbmY5oKnAQQgCEZPA4=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDaDCCAu6gAwIBAgIPWIsuPCu4zaE+GhIJJUMhMAoGCCqGSM49BAMDMFYxCzAJ
|
||||
BgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk
|
||||
MSAwHgYDVQQDDBdlbVNpZ24gUm9vdCBUTFMgQ0EgLSBHMzAeFw0yNTA0MzAxNTM1
|
||||
MDlaFw00MDA0MjgxODMwMDBaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVk
|
||||
aHJhIEluYzEbMBkGA1UEAwwSRU0gRFYgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0C
|
||||
AQYFK4EEACIDYgAEOnp4YsjETTJN3WkDOmeCwO/u/kBV5ooSP6A3G6O9kZRRTuFy
|
||||
pDPjYw8CvRiAN9nlFJ+bd9uUooHfmHsv6oiLdL3+j9pMEJnubKGVZv4+8OX2sJpV
|
||||
bMyLpQVh3xsqRB0Bo4IBljCCAZIwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L
|
||||
WUIgkFQwHQYDVR0OBBYEFK5+EFw8KZbBqEcnBVnx4D3U5QrzMB0GA1UdJQQWMBQG
|
||||
CCsGAQUFBwMBBggrBgEFBQcDAjBdBgNVHSAEVjBUMDkGCysGAQQBg44hAQABMCow
|
||||
KAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB
|
||||
BAGDjiEBAmQwCAYGZ4EMAQIBMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY
|
||||
aHR0cDovL29jc3AtYy5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw
|
||||
b3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNRFZUTFNDQUczQy5wN2MwNwYDVR0f
|
||||
BDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j
|
||||
cmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E
|
||||
AwMDaAAwZQIxAMEN2HWMocbuWdy1d33pH6JpMvP/V/DIS5PtZbv1Q7TXEbxrcyxg
|
||||
yuddOJscYDJJlAIwB4sH1BpbScDzkdD4tJBSwrG/1Mx82vb8YaySehNuu1+1oXNd
|
||||
AEKwaJ0mVzScy2+6
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdDCCAvmgAwIBAgIQAJYaPvsTWVdu0EAFtGhKWzAKBggqhkjOPQQDAzBrMQsw
|
||||
CQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhy
|
||||
YSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290
|
||||
IENBIC0gRzMwHhcNMjQwNzExMTU0MzM2WhcNMzkwNzA5MTgzMDAwWjBWMQswCQYD
|
||||
VQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg
|
||||
MB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwdjAQBgcqhkjOPQIBBgUr
|
||||
gQQAIgNiAARfD9w/q1cWxL6D9bMGH6CQ4u+gAV6GN9s+PwQx9Bl4hC+0iU8QOk8m
|
||||
WO/RwXQy10DCSxT8vSIJClHKp+Ao4qJKdYeV0SwZ7LMQziyLfxIUOY6Grja/sQFw
|
||||
LKYf8EdDXAyjggF1MIIBcTAfBgNVHSMEGDAWgBR8XQKEE9TMipuBzhccLikenEhj
|
||||
QjAdBgNVHQ4EFgQU4TqrIXzx401UrtRyt/2LWUIgkFQwHQYDVR0lBBYwFAYIKwYB
|
||||
BQUHAwEGCCsGAQUFBwMCMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIB
|
||||
FhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMHgGCCsGAQUFBwEBBGwwajAi
|
||||
BggrBgEFBQcwAYYWaHR0cDovL29jc3AuZW1zaWduLmNvbTBEBggrBgEFBQcwAoY4
|
||||
aHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbS9jZXJ0cy9lbVNpZ25FQ0NSb290
|
||||
Q0FHMy5jcnQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbXNpZ24uY29t
|
||||
P1Jvb3RDQUczLmNybDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIB
|
||||
ATAKBggqhkjOPQQDAwNpADBmAjEAt9CIpRGp46QHQYDUBnLKw+vvK0/h9vmilEAg
|
||||
TroUl/anH4x2rXHqiCtBTBfgKDegAjEA8WpG1LTZdAIL0FSYqxXeREaeTSxEofM0
|
||||
1jJH3jGvCXC79LU9UPJ2o3TU+UIj2gMV
|
||||
-----END CERTIFICATE-----
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICQDCCAcagAwIBAgIUUYu3O8bpN1GPvCIHqWpT/FYUNDowCgYIKoZIzj0EAwIw
|
||||
PzELMAkGA1UEBhMCTkwxEzARBgNVBAoMCmVNdWRocmEgQlYxGzAZBgNVBAMMEkVN
|
||||
IEVWIFRMUyBDQSAtIEczQjAeFw0yNjEwMjAwMjIyNDFaFw0yNzA1MDMwMjI3NDFa
|
||||
MDMxMTAvBgNVBAMMKGV2LWczYi1hYWEtZW11ZGhyYS53ZS1oYXZlLWEtcHJvYmxl
|
||||
bS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASjDLpnVdmvXM6R3UB2o42a
|
||||
1GnrYfxRXo7UII36mBl9mIS7p9MkAryhPdxitFHkgTrrbypVtzpydNtJIGGGXUwE
|
||||
o4GrMIGoMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
||||
CCsGAQUFBwMBMDMGA1UdEQQsMCqCKGV2LWczYi1hYWEtZW11ZGhyYS53ZS1oYXZl
|
||||
LWEtcHJvYmxlbS5jb20wHQYDVR0OBBYEFEVBY1ecTN9bLMDl4ifdnN2WZL+WMB8G
|
||||
A1UdIwQYMBaAFD7cINmJRpiHe4c/2IFHslwV2EcGMAoGCCqGSM49BAMCA2gAMGUC
|
||||
MQCyvr9gktgmtsuTuFleFV+YExNNKLf3GZieuUprQcERrzh798oYKavTqZeYf9Kz
|
||||
RhECMCVs1B7KPh7/lgHRly14Z8RJA8ApR7e2cRREW5uPKFOSDlZ/RIezxsfEzsQ4
|
||||
lAODeA==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDzTCCArWgAwIBAgIRANj4aF5PK9nYJAKoWhwetzEwDQYJKoZIhvcNAQELBQAw
|
||||
ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
|
||||
BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNTA1MTQwMDAwMDBaFw0y
|
||||
ODEyMzEyMzU5NTlaMD8xCzAJBgNVBAYTAk5MMRMwEQYDVQQKDAplTXVkaHJhIEJW
|
||||
MRswGQYDVQQDDBJFTSBFViBUTFMgQ0EgLSBHM0IwdjAQBgcqhkjOPQIBBgUrgQQA
|
||||
IgNiAAQl26haZNOX2gsQUunqVG5Ie+/qnJ2daKDF6tz+73Wmm7XW/AH0K/vKbrQL
|
||||
zWTAdn42/9Bdl6gTxaoMbJUw55z18IZkaPE4BkIKpchRhAseJSVA55DktlTDhS7W
|
||||
SvHoZX2jggE0MIIBMDAfBgNVHSMEGDAWgBSgEQojPpbxB+zirynvgqV/0DCktDAd
|
||||
BgNVHQ4EFgQUPtwg2YlGmId7hz/YgUeyXBXYRwYwDgYDVR0PAQH/BAQDAgEGMBIG
|
||||
A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
|
||||
MDAGA1UdIAQpMCcwBwYFZ4EMAQEwDQYLKwYBBAGDjiEBAAEwDQYLKwYBBAGDjiEB
|
||||
AngwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFB
|
||||
Q2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUF
|
||||
BzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQELBQADggEB
|
||||
AJNFuAFW9Gnw/8+kCO4KIlZdnM1Sh2u+8cK0EYAHhXpb5FlGvYkcARigo5oS7VoM
|
||||
7FOYlTueV6yICZKNAYawZPJPhNCGK+rp3cQBEz6d0n8OZEYZov9lb3ll8ORgSDuf
|
||||
FVIW6Gagg/UnOamLBTOR8eD5V73SCme/B2cHUDw+m5E8cc+0Ujzz3Cn3ex5JrhXk
|
||||
2T3s8PoVzEmhTgGboFfcWO1EYhPPrYwdxPYRQIXAXUXhLEOVNL9ASbZJLFI8E1IM
|
||||
m7NwxVN2s38jWpaCUaaF0tg7hfiy7oe13rzJfHsdqldJVTTUTPWVx8TC4ju0VLet
|
||||
bAlwhwFT6AP8uIVMGUHNw24=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,56 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICNzCCAb6gAwIBAgIUPfthO0PYGAYKs9lQ4gp1IOkOr2MwCgYIKoZIzj0EAwIw
|
||||
PzELMAkGA1UEBhMCTkwxEzARBgNVBAoMCmVNdWRocmEgQlYxGzAZBgNVBAMMEkVN
|
||||
IEVWIFRMUyBDQSAtIEczQjAeFw0yNjEwMjAwMDU5MzZaFw0yNzA1MDMwMTA0MzZa
|
||||
MC8xLTArBgNVBAMMJGV2LWczYi1lbXVkaHJhLndlLWhhdmUtYS1wcm9ibGVtLmNv
|
||||
bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPZPwlA3io/AX/pMwu0dNl9WMxrr
|
||||
C9j/xMLHgG72cWVzoX62REmvp9zyXQ04kHP9/sW6KnCcm5ZZ5i4YoJbDPASjgacw
|
||||
gaQwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYB
|
||||
BQUHAwEwLwYDVR0RBCgwJoIkZXYtZzNiLWVtdWRocmEud2UtaGF2ZS1hLXByb2Js
|
||||
ZW0uY29tMB0GA1UdDgQWBBSvX4QR4ERW5uNUaMq0yYzXCZf0ZjAfBgNVHSMEGDAW
|
||||
gBQ+3CDZiUaYh3uHP9iBR7JcFdhHBjAKBggqhkjOPQQDAgNnADBkAjACy/uJR01M
|
||||
/O9IEZyRHX1LSU28bmg542K0IX9jDRTrZXUqkDWfiZIL7xfnrRrBpHoCMFbBIaOa
|
||||
WwWtFtDg9ZqQvktsWS950u5qfW1sChgWNya/E3IMKFgtoHm2xrZsmfwLSQ==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDaDCCAu2gAwIBAgIQAMfEHv6S2CXwXq6EGkqCwTAKBggqhkjOPQQDAzBWMQsw
|
||||
CQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl
|
||||
ZDEgMB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwHhcNMjUwNDMwMTYw
|
||||
MzMxWhcNNDAwNDI4MTgzMDAwWjA/MQswCQYDVQQGEwJOTDETMBEGA1UECgwKZU11
|
||||
ZGhyYSBCVjEbMBkGA1UEAwwSRU0gRVYgVExTIENBIC0gRzNCMHYwEAYHKoZIzj0C
|
||||
AQYFK4EEACIDYgAEJduoWmTTl9oLEFLp6lRuSHvv6pydnWigxerc/u91ppu11vwB
|
||||
9Cv7ym60C81kwHZ+Nv/QXZeoE8WqDGyVMOec9fCGZGjxOAZCCqXIUYQLHiUlQOeQ
|
||||
5LZUw4Uu1krx6GV9o4IBlTCCAZEwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L
|
||||
WUIgkFQwHQYDVR0OBBYEFD7cINmJRpiHe4c/2IFHslwV2EcGMB0GA1UdJQQWMBQG
|
||||
CCsGAQUFBwMBBggrBgEFBQcDAjBcBgNVHSAEVTBTMDkGCysGAQQBg44hAQABMCow
|
||||
KAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB
|
||||
BAGDjiEBAngwBwYFZ4EMAQEwdQYIKwYBBQUHAQEEaTBnMCQGCCsGAQUFBzABhhho
|
||||
dHRwOi8vb2NzcC1iLmVtc2lnbi5jb20wPwYIKwYBBQUHMAKGM2h0dHA6Ly9yZXBv
|
||||
c2l0b3J5LmVtc2lnbi5jb20vY2VydHMvRU1FVlRMU0NBRzNCLnA3YzA3BgNVHR8E
|
||||
MDAuMCygKqAohiZodHRwOi8vY3JsLmVtc2lnbi5jb20vP3Jvb3R0bHNjYWczLmNy
|
||||
bDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAKBggqhkjOPQQD
|
||||
AwNpADBmAjEA9Jq999oaOUKhFwopw33iCmt0OHIn3gjT43GfuOHR/YckXdwoNdDA
|
||||
lIEhz0NgRO3/AjEAvY/a3OMvktIZLYjn+WLKmp0QhrIMV+e6EpS7j4GVeOKouNp6
|
||||
MN/P+ByGeiRMghzB
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdDCCAvmgAwIBAgIQAJYaPvsTWVdu0EAFtGhKWzAKBggqhkjOPQQDAzBrMQsw
|
||||
CQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhy
|
||||
YSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290
|
||||
IENBIC0gRzMwHhcNMjQwNzExMTU0MzM2WhcNMzkwNzA5MTgzMDAwWjBWMQswCQYD
|
||||
VQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg
|
||||
MB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwdjAQBgcqhkjOPQIBBgUr
|
||||
gQQAIgNiAARfD9w/q1cWxL6D9bMGH6CQ4u+gAV6GN9s+PwQx9Bl4hC+0iU8QOk8m
|
||||
WO/RwXQy10DCSxT8vSIJClHKp+Ao4qJKdYeV0SwZ7LMQziyLfxIUOY6Grja/sQFw
|
||||
LKYf8EdDXAyjggF1MIIBcTAfBgNVHSMEGDAWgBR8XQKEE9TMipuBzhccLikenEhj
|
||||
QjAdBgNVHQ4EFgQU4TqrIXzx401UrtRyt/2LWUIgkFQwHQYDVR0lBBYwFAYIKwYB
|
||||
BQUHAwEGCCsGAQUFBwMCMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIB
|
||||
FhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMHgGCCsGAQUFBwEBBGwwajAi
|
||||
BggrBgEFBQcwAYYWaHR0cDovL29jc3AuZW1zaWduLmNvbTBEBggrBgEFBQcwAoY4
|
||||
aHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbS9jZXJ0cy9lbVNpZ25FQ0NSb290
|
||||
Q0FHMy5jcnQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbXNpZ24uY29t
|
||||
P1Jvb3RDQUczLmNybDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIB
|
||||
ATAKBggqhkjOPQQDAwNpADBmAjEAt9CIpRGp46QHQYDUBnLKw+vvK0/h9vmilEAg
|
||||
TroUl/anH4x2rXHqiCtBTBfgKDegAjEA8WpG1LTZdAIL0FSYqxXeREaeTSxEofM0
|
||||
1jJH3jGvCXC79LU9UPJ2o3TU+UIj2gMV
|
||||
-----END CERTIFICATE-----
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICQDCCAcegAwIBAgIUTMUrGzSU+0BySFdrN3ALZq9Spv8wCgYIKoZIzj0EAwIw
|
||||
QDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC2VNdWRocmEgSW5jMRswGQYDVQQDDBJF
|
||||
TSBFViBUTFMgQ0EgLSBHM0MwHhcNMjYxMDIwMDIyMjQyWhcNMjcwNTAzMDIyNzQy
|
||||
WjAzMTEwLwYDVQQDDChldi1nM2MtYWFhLWVtdWRocmEud2UtaGF2ZS1hLXByb2Js
|
||||
ZW0uY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEglClDbotLFFeY9SpryT4
|
||||
k958tvriY2DDnaPsmjQaecRhB6+L/8hLw6FMt+HT8SLvjIZnFY+AH92cBjedcNST
|
||||
AKOBqzCBqDAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAK
|
||||
BggrBgEFBQcDATAzBgNVHREELDAqgihldi1nM2MtYWFhLWVtdWRocmEud2UtaGF2
|
||||
ZS1hLXByb2JsZW0uY29tMB0GA1UdDgQWBBSVtGbn6xUT1iosUeaGA15Nq640aTAf
|
||||
BgNVHSMEGDAWgBSmJV6AqU2385Z8G8eR35K87kvrXzAKBggqhkjOPQQDAgNnADBk
|
||||
AjAg7b5bIK9X50QEX0U6G8fQh12BnFQ079Iluzd0Y2TJWCjtVXZi3nOciM8RzNKM
|
||||
tZECMCBf0JOyMt8RNS93Wj8kYbWkCtoKoUrqx7G3JTfGReKci+DdTvkF8/3F6doi
|
||||
9KB22Q==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDzTCCArWgAwIBAgIQBfB4dS3s56G7hZXTAxZxcTANBgkqhkiG9w0BAQsFADB7
|
||||
MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
|
||||
VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE
|
||||
AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTI1MDUxNDAwMDAwMFoXDTI4
|
||||
MTIzMTIzNTk1OVowQDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC2VNdWRocmEgSW5j
|
||||
MRswGQYDVQQDDBJFTSBFViBUTFMgQ0EgLSBHM0MwdjAQBgcqhkjOPQIBBgUrgQQA
|
||||
IgNiAAQtVugppvuCxkpGl9lgr5UekGeukfkm00MG2kioqut4abamfm0nQm4EQqoD
|
||||
s24ZiN/2NlFO4c8H9bpLP/KgZkWufTHVhmrTGqPSRusLMXfumct1ZsUWznSAimaP
|
||||
kfDEf8qjggE0MIIBMDAfBgNVHSMEGDAWgBSgEQojPpbxB+zirynvgqV/0DCktDAd
|
||||
BgNVHQ4EFgQUpiVegKlNt/OWfBvHkd+SvO5L618wDgYDVR0PAQH/BAQDAgEGMBIG
|
||||
A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
|
||||
MDAGA1UdIAQpMCcwBwYFZ4EMAQEwDQYLKwYBBAGDjiEBAAEwDQYLKwYBBAGDjiEB
|
||||
AngwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFB
|
||||
Q2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUF
|
||||
BzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQELBQADggEB
|
||||
AIFfHiaMSjnrdZygRYV4ekRBmG7ybcFk4hGQWMMyMFi0cAEk2+dGfz5bl8IaIbLq
|
||||
z+uVJzhOgVEX7WqIfgbWfFsfPYHYjPHBmy7SlZ3BwA86IQ6qF/etpX2/qL9A5yRN
|
||||
N3nVowUpaqV6H3aCpkAh3wR2ZNkvAbLDvPz3J0l+sEWjWv+ZISOV4R+hXDTdPXV0
|
||||
1lKxnbwqEsdo/sE2QkCDKwFrZh/0uKjWspydJj+jSaDLTrGNx50Dgmn7VEcD1ZI5
|
||||
FXjknVUiO25YlmS1dtVZSBbyUKSjlrP/yDwPcZunoAsmCAAtCKsFLviLaymzvsKI
|
||||
eSSDGxpSySp2VCxompGDk8g=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,56 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICOTCCAb+gAwIBAgIUOcw5N4XGLiB/3GvB05bJuGoZPR0wCgYIKoZIzj0EAwIw
|
||||
QDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC2VNdWRocmEgSW5jMRswGQYDVQQDDBJF
|
||||
TSBFViBUTFMgQ0EgLSBHM0MwHhcNMjYxMDIwMDA1OTM3WhcNMjcwNTAzMDEwNDM3
|
||||
WjAvMS0wKwYDVQQDDCRldi1nM2MtZW11ZGhyYS53ZS1oYXZlLWEtcHJvYmxlbS5j
|
||||
b20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQo7U02MAUO8EEMomXwIl+kSQzm
|
||||
b+nvXKIZ/hC4rZ1GpXchv4SzTrV1SB/Qg+pD6OBEXbBBnPmQNkePNQTlujqRo4Gn
|
||||
MIGkMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsG
|
||||
AQUFBwMBMC8GA1UdEQQoMCaCJGV2LWczYy1lbXVkaHJhLndlLWhhdmUtYS1wcm9i
|
||||
bGVtLmNvbTAdBgNVHQ4EFgQUqxe+7qS+MxNyioJZhQsL5MEEw6swHwYDVR0jBBgw
|
||||
FoAUpiVegKlNt/OWfBvHkd+SvO5L618wCgYIKoZIzj0EAwIDaAAwZQIwC/CxSIov
|
||||
wcar3sV98B8cL+QuR2kkJdLdXsFKzg/HDSJ1MOjqTGm924LB6r9nl0f7AjEAzcwr
|
||||
WQOYY9eycqIz+LG2daYS6LOctj+CjoAk/CLugWPxGxp4Aerfau2P1z1h5jAA
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDaDCCAu6gAwIBAgIQAIAJkopkEHYBrwX6LxnxCTAKBggqhkjOPQQDAzBWMQsw
|
||||
CQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl
|
||||
ZDEgMB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwHhcNMjUwNDMwMTUz
|
||||
OTMxWhcNNDAwNDI4MTgzMDAwWjBAMQswCQYDVQQGEwJVUzEUMBIGA1UECgwLZU11
|
||||
ZGhyYSBJbmMxGzAZBgNVBAMMEkVNIEVWIFRMUyBDQSAtIEczQzB2MBAGByqGSM49
|
||||
AgEGBSuBBAAiA2IABC1W6Cmm+4LGSkaX2WCvlR6QZ66R+SbTQwbaSKiq63hptqZ+
|
||||
bSdCbgRCqgOzbhmI3/Y2UU7hzwf1uks/8qBmRa59MdWGatMao9JG6wsxd+6Zy3Vm
|
||||
xRbOdICKZo+R8MR/yqOCAZUwggGRMB8GA1UdIwQYMBaAFOE6qyF88eNNVK7Ucrf9
|
||||
i1lCIJBUMB0GA1UdDgQWBBSmJV6AqU2385Z8G8eR35K87kvrXzAdBgNVHSUEFjAU
|
||||
BggrBgEFBQcDAQYIKwYBBQUHAwIwXAYDVR0gBFUwUzA5BgsrBgEEAYOOIQEAATAq
|
||||
MCgGCCsGAQUFBwIBFhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMA0GCysG
|
||||
AQQBg44hAQJ4MAcGBWeBDAEBMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY
|
||||
aHR0cDovL29jc3AtYy5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw
|
||||
b3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNRVZUTFNDQUczQy5wN2MwNwYDVR0f
|
||||
BDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j
|
||||
cmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E
|
||||
AwMDaAAwZQIwBy1wTnzH4lXDTy2PD91ysLjvnlVN3JbJmc1BIMEU8TOLkYVHibMc
|
||||
9HeyonikFSfmAjEA6uE3QRxlrZTz/1/lXPTEMUhoauAtycagtlNFp79kjhvNa2/f
|
||||
Aal1GNxsOutLnr0Y
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdDCCAvmgAwIBAgIQAJYaPvsTWVdu0EAFtGhKWzAKBggqhkjOPQQDAzBrMQsw
|
||||
CQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhy
|
||||
YSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290
|
||||
IENBIC0gRzMwHhcNMjQwNzExMTU0MzM2WhcNMzkwNzA5MTgzMDAwWjBWMQswCQYD
|
||||
VQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg
|
||||
MB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwdjAQBgcqhkjOPQIBBgUr
|
||||
gQQAIgNiAARfD9w/q1cWxL6D9bMGH6CQ4u+gAV6GN9s+PwQx9Bl4hC+0iU8QOk8m
|
||||
WO/RwXQy10DCSxT8vSIJClHKp+Ao4qJKdYeV0SwZ7LMQziyLfxIUOY6Grja/sQFw
|
||||
LKYf8EdDXAyjggF1MIIBcTAfBgNVHSMEGDAWgBR8XQKEE9TMipuBzhccLikenEhj
|
||||
QjAdBgNVHQ4EFgQU4TqrIXzx401UrtRyt/2LWUIgkFQwHQYDVR0lBBYwFAYIKwYB
|
||||
BQUHAwEGCCsGAQUFBwMCMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIB
|
||||
FhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMHgGCCsGAQUFBwEBBGwwajAi
|
||||
BggrBgEFBQcwAYYWaHR0cDovL29jc3AuZW1zaWduLmNvbTBEBggrBgEFBQcwAoY4
|
||||
aHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbS9jZXJ0cy9lbVNpZ25FQ0NSb290
|
||||
Q0FHMy5jcnQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbXNpZ24uY29t
|
||||
P1Jvb3RDQUczLmNybDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIB
|
||||
ATAKBggqhkjOPQQDAwNpADBmAjEAt9CIpRGp46QHQYDUBnLKw+vvK0/h9vmilEAg
|
||||
TroUl/anH4x2rXHqiCtBTBfgKDegAjEA8WpG1LTZdAIL0FSYqxXeREaeTSxEofM0
|
||||
1jJH3jGvCXC79LU9UPJ2o3TU+UIj2gMV
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,466 +0,0 @@
|
||||
[
|
||||
{
|
||||
"name": "EM DV TLS CA - G3B",
|
||||
"usage": "tls",
|
||||
"issued_by": "emSign Root TLS CA - G3",
|
||||
"issuer_operator": "eMudhra",
|
||||
"issuer_sha256": "7DD78D5F4F13459A83DFF9ABBBA62EDBAF6F2D102BF257FD712F4D9F2746ED8D",
|
||||
"subject": "CN=EM DV TLS CA - G3B,O=eMudhra BV,C=NL",
|
||||
"issuer": "CN=emSign Root TLS CA - G3,O=eMudhra Technologies Limited,C=IN",
|
||||
"serial_hex": "A4AEE678F23362B4C0E460B772F214",
|
||||
"sha256": "42C4ACCD12C4F59597925E1A08A7A90102608543809308D50EC427E118BA1493",
|
||||
"spki_sha256": "EBED6475C2C2D80FCB199F3FE8DD6E6B3CE60B77EB15D4E42C3DEC0C6F5B5105",
|
||||
"subject_key_identifier": "E21E2FE71C19390E554B62C120245735248A2514",
|
||||
"authority_key_identifier": "E13AAB217CF1E34D54AED472B7FD8B5942209054",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "ecdsa-with-SHA384",
|
||||
"not_before": "2025-04-30T15:54:08Z",
|
||||
"not_after": "2040-04-28T18:30:00Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-18T09:24:32Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.emsign.com/?roottlscag3.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDaDCCAu6gAwIBAgIQAKSu5njyM2K0wORgt3LyFDAKBggqhkjOPQQDAzBWMQsw\nCQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl\nZDEgMB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwHhcNMjUwNDMwMTU1\nNDA4WhcNNDAwNDI4MTgzMDAwWjA/MQswCQYDVQQGEwJOTDETMBEGA1UECgwKZU11\nZGhyYSBCVjEbMBkGA1UEAwwSRU0gRFYgVExTIENBIC0gRzNCMHYwEAYHKoZIzj0C\nAQYFK4EEACIDYgAE557ZwEqXc8RzXlERHahawr1eZKs3S4DhLLwgOOweTw47gS/J\nhZ4eZ6+wTi+LyX90hbplqpEe6KTkW2LVzAPVa+Z4s8OMtNyTfKJGDiOEU8iSk10p\n1E+R4VYGtjzO2rRoo4IBljCCAZIwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L\nWUIgkFQwHQYDVR0OBBYEFOIeL+ccGTkOVUtiwSAkVzUkiiUUMB0GA1UdJQQWMBQG\nCCsGAQUFBwMBBggrBgEFBQcDAjBdBgNVHSAEVjBUMDkGCysGAQQBg44hAQABMCow\nKAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB\nBAGDjiEBAmQwCAYGZ4EMAQIBMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY\naHR0cDovL29jc3AtYi5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw\nb3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNRFZUTFNDQUczQi5wN2MwNwYDVR0f\nBDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j\ncmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E\nAwMDaAAwZQIwLmsGXi6oFMJ2klkcEMXMug6gvxQWZWkewiDWVzQyl2L6z6DuQfPO\nIbh1grvdULDCAjEAxZvLlxUavG69J6wnSjC8XBbqNIQsJ6CE2QdNOe84Ptxb6VG8\ngt2TlfJbHii+KNvK\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM DV TLS CA - G3B",
|
||||
"usage": "tls",
|
||||
"issued_by": "AAA Certificate Services",
|
||||
"issuer_operator": "Sectigo",
|
||||
"issuer_sha256": "D7A7A0FB5D7E2731D771E9484EBCDEF71D5F0C3E0A2948782BC83EE0EA699EF4",
|
||||
"subject": "CN=EM DV TLS CA - G3B,O=eMudhra BV,C=NL",
|
||||
"issuer": "CN=AAA Certificate Services,O=Comodo CA Limited,L=Salford,ST=Greater Manchester,C=GB",
|
||||
"serial_hex": "A024FDF4BA665C785CE4A020483858B7",
|
||||
"sha256": "45A883F349AEDFD5F3A649B5498FFB121712BA8B448F3F2A91DBC5A766FCDDBE",
|
||||
"spki_sha256": "EBED6475C2C2D80FCB199F3FE8DD6E6B3CE60B77EB15D4E42C3DEC0C6F5B5105",
|
||||
"subject_key_identifier": "E21E2FE71C19390E554B62C120245735248A2514",
|
||||
"authority_key_identifier": "A0110A233E96F107ECE2AF29EF82A57FD030A4B4",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "sha256WithRSAEncryption",
|
||||
"not_before": "2025-05-14T00:00:00Z",
|
||||
"not_after": "2028-12-31T23:59:59Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-19T10:35:36Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.comodoca.com/AAACertificateServices.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDzjCCAragAwIBAgIRAKAk/fS6Zlx4XOSgIEg4WLcwDQYJKoZIhvcNAQELBQAw\nezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV\nBAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNTA1MTQwMDAwMDBaFw0y\nODEyMzEyMzU5NTlaMD8xCzAJBgNVBAYTAk5MMRMwEQYDVQQKDAplTXVkaHJhIEJW\nMRswGQYDVQQDDBJFTSBEViBUTFMgQ0EgLSBHM0IwdjAQBgcqhkjOPQIBBgUrgQQA\nIgNiAATnntnASpdzxHNeUREdqFrCvV5kqzdLgOEsvCA47B5PDjuBL8mFnh5nr7BO\nL4vJf3SFumWqkR7opORbYtXMA9Vr5nizw4y03JN8okYOI4RTyJKTXSnUT5HhVga2\nPM7atGijggE1MIIBMTAfBgNVHSMEGDAWgBSgEQojPpbxB+zirynvgqV/0DCktDAd\nBgNVHQ4EFgQU4h4v5xwZOQ5VS2LBICRXNSSKJRQwDgYDVR0PAQH/BAQDAgEGMBIG\nA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC\nMDEGA1UdIAQqMCgwCAYGZ4EMAQIBMA0GCysGAQQBg44hAQABMA0GCysGAQQBg44h\nAQJkMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FB\nQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEF\nBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUAA4IB\nAQBzQ1IoqpdotM6gFrR4Q3YrKifOLeaj5XXunldpVE/vZn2TxC2y0s8oYiLR5ICE\nwqVXSB7N6BM1Mp+Nif7Jbhb2IswAfSR4Iik8+B0iRmi7lYoNlycCgHjmsjOmZaxM\nQkPmjXAJbG5f4V41OsvJZmS7lI3r0IuvEDVX3GAZ13on6IImSs9ybNpHQ7NCqkMQ\n7wH4uAO1dtpFycgJSdHaCOhHjrox2BTYGLdpUrYwY3EOAjlZ8UGgsxs7mG+xquMl\nbN1LFURwfnkVMP3T/DBIZ/ys2+lNFyxK3FlArrV4/000uTnVB1lO8oGORYdXoT5V\nGUyRCEIDhF5TBUuKF4E3kf1h\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM OV TLS CA - G3B",
|
||||
"usage": "tls",
|
||||
"issued_by": "emSign Root TLS CA - G3",
|
||||
"issuer_operator": "eMudhra",
|
||||
"issuer_sha256": "7DD78D5F4F13459A83DFF9ABBBA62EDBAF6F2D102BF257FD712F4D9F2746ED8D",
|
||||
"subject": "CN=EM OV TLS CA - G3B,O=eMudhra BV,C=NL",
|
||||
"issuer": "CN=emSign Root TLS CA - G3,O=eMudhra Technologies Limited,C=IN",
|
||||
"serial_hex": "6CADA367FB1C100088120EA202D568",
|
||||
"sha256": "98B896625C0C230ADEEC3EB2CF6AAD5001ECF9156A68644E82374CE5833BC25B",
|
||||
"spki_sha256": "43BFFA19D6EF651451F6841E019931E96F6F2EAEFF28AB4B6F1CE4576DE2717B",
|
||||
"subject_key_identifier": "9BD86551AFE7E72C37AD08EE6919D9BF3784AE0A",
|
||||
"authority_key_identifier": "E13AAB217CF1E34D54AED472B7FD8B5942209054",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "ecdsa-with-SHA384",
|
||||
"not_before": "2025-04-30T16:00:12Z",
|
||||
"not_after": "2040-04-28T18:30:00Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-18T09:37:19Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.emsign.com/?roottlscag3.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDZjCCAu2gAwIBAgIPbK2jZ/scEACIEg6iAtVoMAoGCCqGSM49BAMDMFYxCzAJ\nBgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk\nMSAwHgYDVQQDDBdlbVNpZ24gUm9vdCBUTFMgQ0EgLSBHMzAeFw0yNTA0MzAxNjAw\nMTJaFw00MDA0MjgxODMwMDBaMD8xCzAJBgNVBAYTAk5MMRMwEQYDVQQKDAplTXVk\naHJhIEJWMRswGQYDVQQDDBJFTSBPViBUTFMgQ0EgLSBHM0IwdjAQBgcqhkjOPQIB\nBgUrgQQAIgNiAARziXqg6zz9yosSQC/68KvE4SErr43ud4rJ7i1tuD+sKAxeBWOK\n56Ks1xwyKo42HN659pxDArndjXPRzGyqsswK7k4hbOl53VGKSvS2JuVoTN1lgDft\nDIVOTMEvTPhkbQ2jggGWMIIBkjAfBgNVHSMEGDAWgBThOqshfPHjTVSu1HK3/YtZ\nQiCQVDAdBgNVHQ4EFgQUm9hlUa/n5yw3rQjuaRnZvzeErgowHQYDVR0lBBYwFAYI\nKwYBBQUHAwEGCCsGAQUFBwMCMF0GA1UdIARWMFQwOQYLKwYBBAGDjiEBAAEwKjAo\nBggrBgEFBQcCARYcaHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbTANBgsrBgEE\nAYOOIQECbjAIBgZngQwBAgIwdQYIKwYBBQUHAQEEaTBnMCQGCCsGAQUFBzABhhho\ndHRwOi8vb2NzcC1iLmVtc2lnbi5jb20wPwYIKwYBBQUHMAKGM2h0dHA6Ly9yZXBv\nc2l0b3J5LmVtc2lnbi5jb20vY2VydHMvRU1PVlRMU0NBRzNCLnA3YzA3BgNVHR8E\nMDAuMCygKqAohiZodHRwOi8vY3JsLmVtc2lnbi5jb20vP3Jvb3R0bHNjYWczLmNy\nbDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAKBggqhkjOPQQD\nAwNnADBkAjBAk+5BizdJhrED3wb7F2Gm7bWI60dlNd075nghT2TrR4NWKZtJZcbc\n28xxIY/NONICMF6mPdsjosaqmvEMWqKcBh4vsIvXSKnQj5o8zrFB4oKS+accjYTe\n8Dz3bQjauvy9uw==\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM OV TLS CA - G3B",
|
||||
"usage": "tls",
|
||||
"issued_by": "AAA Certificate Services",
|
||||
"issuer_operator": "Sectigo",
|
||||
"issuer_sha256": "D7A7A0FB5D7E2731D771E9484EBCDEF71D5F0C3E0A2948782BC83EE0EA699EF4",
|
||||
"subject": "CN=EM OV TLS CA - G3B,O=eMudhra BV,C=NL",
|
||||
"issuer": "CN=AAA Certificate Services,O=Comodo CA Limited,L=Salford,ST=Greater Manchester,C=GB",
|
||||
"serial_hex": "E94223BDE92F914E5AB9ACABFDAC3710",
|
||||
"sha256": "5F1DED4DD590AF74631290CF073B122A2AAC6A1FA479778A0BD43579BD832699",
|
||||
"spki_sha256": "43BFFA19D6EF651451F6841E019931E96F6F2EAEFF28AB4B6F1CE4576DE2717B",
|
||||
"subject_key_identifier": "9BD86551AFE7E72C37AD08EE6919D9BF3784AE0A",
|
||||
"authority_key_identifier": "A0110A233E96F107ECE2AF29EF82A57FD030A4B4",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "sha256WithRSAEncryption",
|
||||
"not_before": "2025-05-14T00:00:00Z",
|
||||
"not_after": "2028-12-31T23:59:59Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-19T10:35:36Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.comodoca.com/AAACertificateServices.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDzjCCAragAwIBAgIRAOlCI73pL5FOWrmsq/2sNxAwDQYJKoZIhvcNAQELBQAw\nezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV\nBAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNTA1MTQwMDAwMDBaFw0y\nODEyMzEyMzU5NTlaMD8xCzAJBgNVBAYTAk5MMRMwEQYDVQQKDAplTXVkaHJhIEJW\nMRswGQYDVQQDDBJFTSBPViBUTFMgQ0EgLSBHM0IwdjAQBgcqhkjOPQIBBgUrgQQA\nIgNiAARziXqg6zz9yosSQC/68KvE4SErr43ud4rJ7i1tuD+sKAxeBWOK56Ks1xwy\nKo42HN659pxDArndjXPRzGyqsswK7k4hbOl53VGKSvS2JuVoTN1lgDftDIVOTMEv\nTPhkbQ2jggE1MIIBMTAfBgNVHSMEGDAWgBSgEQojPpbxB+zirynvgqV/0DCktDAd\nBgNVHQ4EFgQUm9hlUa/n5yw3rQjuaRnZvzeErgowDgYDVR0PAQH/BAQDAgEGMBIG\nA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC\nMDEGA1UdIAQqMCgwCAYGZ4EMAQICMA0GCysGAQQBg44hAQABMA0GCysGAQQBg44h\nAQJuMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FB\nQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEF\nBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUAA4IB\nAQALRoOSvkzRa+tN5Rje9W5GiXd/qsicd9N6Gnh0SWC7VyWH+HycIqAnFCMYZznj\nCeGusomFYHE42SHWr85JDIbgzy6y3dO4i9n9w0Bx7yrXWBbDzFS8VgA3+EY4Cg7y\nmtoC3RPOJVtaXXPZ+68X804g1Mj+3vCSHj2lNPVgco0OzSIOJ/KMg1R9MLBkiKzb\nbERAGZHejY0HBhYd76IINZN8z6bBNah2UdFYxsOisLynPQUkol6gRLum024/FzVl\nCCDfnUusrkr+mAfPAvD/Vb8bhpA7jYtepuU+2mIdShj5lLlvAwZphn+ypWycuo2x\n0k9mldz2dqI9nhCiY+TTIOOR\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM EV TLS CA - G3B",
|
||||
"usage": "tls",
|
||||
"issued_by": "emSign Root TLS CA - G3",
|
||||
"issuer_operator": "eMudhra",
|
||||
"issuer_sha256": "7DD78D5F4F13459A83DFF9ABBBA62EDBAF6F2D102BF257FD712F4D9F2746ED8D",
|
||||
"subject": "CN=EM EV TLS CA - G3B,O=eMudhra BV,C=NL",
|
||||
"issuer": "CN=emSign Root TLS CA - G3,O=eMudhra Technologies Limited,C=IN",
|
||||
"serial_hex": "C7C41EFE92D825F05EAE841A4A82C1",
|
||||
"sha256": "E7568FE6E12331F4FD7DE61DA4C7559D0F8EB192A218D4741A3BA75184333838",
|
||||
"spki_sha256": "E0254C7FCDC265E2F0F8A428DABB75AB4AE039B4872D62F5EE57F0877D5A8A41",
|
||||
"subject_key_identifier": "3EDC20D9894698877B873FD88147B25C15D84706",
|
||||
"authority_key_identifier": "E13AAB217CF1E34D54AED472B7FD8B5942209054",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "ecdsa-with-SHA384",
|
||||
"not_before": "2025-04-30T16:03:31Z",
|
||||
"not_after": "2040-04-28T18:30:00Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-18T09:28:53Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.emsign.com/?roottlscag3.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDaDCCAu2gAwIBAgIQAMfEHv6S2CXwXq6EGkqCwTAKBggqhkjOPQQDAzBWMQsw\nCQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl\nZDEgMB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwHhcNMjUwNDMwMTYw\nMzMxWhcNNDAwNDI4MTgzMDAwWjA/MQswCQYDVQQGEwJOTDETMBEGA1UECgwKZU11\nZGhyYSBCVjEbMBkGA1UEAwwSRU0gRVYgVExTIENBIC0gRzNCMHYwEAYHKoZIzj0C\nAQYFK4EEACIDYgAEJduoWmTTl9oLEFLp6lRuSHvv6pydnWigxerc/u91ppu11vwB\n9Cv7ym60C81kwHZ+Nv/QXZeoE8WqDGyVMOec9fCGZGjxOAZCCqXIUYQLHiUlQOeQ\n5LZUw4Uu1krx6GV9o4IBlTCCAZEwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L\nWUIgkFQwHQYDVR0OBBYEFD7cINmJRpiHe4c/2IFHslwV2EcGMB0GA1UdJQQWMBQG\nCCsGAQUFBwMBBggrBgEFBQcDAjBcBgNVHSAEVTBTMDkGCysGAQQBg44hAQABMCow\nKAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB\nBAGDjiEBAngwBwYFZ4EMAQEwdQYIKwYBBQUHAQEEaTBnMCQGCCsGAQUFBzABhhho\ndHRwOi8vb2NzcC1iLmVtc2lnbi5jb20wPwYIKwYBBQUHMAKGM2h0dHA6Ly9yZXBv\nc2l0b3J5LmVtc2lnbi5jb20vY2VydHMvRU1FVlRMU0NBRzNCLnA3YzA3BgNVHR8E\nMDAuMCygKqAohiZodHRwOi8vY3JsLmVtc2lnbi5jb20vP3Jvb3R0bHNjYWczLmNy\nbDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAKBggqhkjOPQQD\nAwNpADBmAjEA9Jq999oaOUKhFwopw33iCmt0OHIn3gjT43GfuOHR/YckXdwoNdDA\nlIEhz0NgRO3/AjEAvY/a3OMvktIZLYjn+WLKmp0QhrIMV+e6EpS7j4GVeOKouNp6\nMN/P+ByGeiRMghzB\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM EV TLS CA - G3B",
|
||||
"usage": "tls",
|
||||
"issued_by": "AAA Certificate Services",
|
||||
"issuer_operator": "Sectigo",
|
||||
"issuer_sha256": "D7A7A0FB5D7E2731D771E9484EBCDEF71D5F0C3E0A2948782BC83EE0EA699EF4",
|
||||
"subject": "CN=EM EV TLS CA - G3B,O=eMudhra BV,C=NL",
|
||||
"issuer": "CN=AAA Certificate Services,O=Comodo CA Limited,L=Salford,ST=Greater Manchester,C=GB",
|
||||
"serial_hex": "D8F8685E4F2BD9D82402A85A1C1EB731",
|
||||
"sha256": "579480AEA166290BD3C643589E795FC0D0E54E86505D180F1DFF99EFD3199512",
|
||||
"spki_sha256": "E0254C7FCDC265E2F0F8A428DABB75AB4AE039B4872D62F5EE57F0877D5A8A41",
|
||||
"subject_key_identifier": "3EDC20D9894698877B873FD88147B25C15D84706",
|
||||
"authority_key_identifier": "A0110A233E96F107ECE2AF29EF82A57FD030A4B4",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "sha256WithRSAEncryption",
|
||||
"not_before": "2025-05-14T00:00:00Z",
|
||||
"not_after": "2028-12-31T23:59:59Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-19T10:35:36Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.comodoca.com/AAACertificateServices.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDzTCCArWgAwIBAgIRANj4aF5PK9nYJAKoWhwetzEwDQYJKoZIhvcNAQELBQAw\nezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV\nBAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNTA1MTQwMDAwMDBaFw0y\nODEyMzEyMzU5NTlaMD8xCzAJBgNVBAYTAk5MMRMwEQYDVQQKDAplTXVkaHJhIEJW\nMRswGQYDVQQDDBJFTSBFViBUTFMgQ0EgLSBHM0IwdjAQBgcqhkjOPQIBBgUrgQQA\nIgNiAAQl26haZNOX2gsQUunqVG5Ie+/qnJ2daKDF6tz+73Wmm7XW/AH0K/vKbrQL\nzWTAdn42/9Bdl6gTxaoMbJUw55z18IZkaPE4BkIKpchRhAseJSVA55DktlTDhS7W\nSvHoZX2jggE0MIIBMDAfBgNVHSMEGDAWgBSgEQojPpbxB+zirynvgqV/0DCktDAd\nBgNVHQ4EFgQUPtwg2YlGmId7hz/YgUeyXBXYRwYwDgYDVR0PAQH/BAQDAgEGMBIG\nA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC\nMDAGA1UdIAQpMCcwBwYFZ4EMAQEwDQYLKwYBBAGDjiEBAAEwDQYLKwYBBAGDjiEB\nAngwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFB\nQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUF\nBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQELBQADggEB\nAJNFuAFW9Gnw/8+kCO4KIlZdnM1Sh2u+8cK0EYAHhXpb5FlGvYkcARigo5oS7VoM\n7FOYlTueV6yICZKNAYawZPJPhNCGK+rp3cQBEz6d0n8OZEYZov9lb3ll8ORgSDuf\nFVIW6Gagg/UnOamLBTOR8eD5V73SCme/B2cHUDw+m5E8cc+0Ujzz3Cn3ex5JrhXk\n2T3s8PoVzEmhTgGboFfcWO1EYhPPrYwdxPYRQIXAXUXhLEOVNL9ASbZJLFI8E1IM\nm7NwxVN2s38jWpaCUaaF0tg7hfiy7oe13rzJfHsdqldJVTTUTPWVx8TC4ju0VLet\nbAlwhwFT6AP8uIVMGUHNw24=\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM DV TLS CA - G3C",
|
||||
"usage": "tls",
|
||||
"issued_by": "emSign Root TLS CA - G3",
|
||||
"issuer_operator": "eMudhra",
|
||||
"issuer_sha256": "7DD78D5F4F13459A83DFF9ABBBA62EDBAF6F2D102BF257FD712F4D9F2746ED8D",
|
||||
"subject": "CN=EM DV TLS CA - G3C,O=eMudhra Inc,C=US",
|
||||
"issuer": "CN=emSign Root TLS CA - G3,O=eMudhra Technologies Limited,C=IN",
|
||||
"serial_hex": "588B2E3C2BB8CDA13E1A1209254321",
|
||||
"sha256": "0164D7CEAE5BB909C272AF151FF44B1177AE9B47D9424B94F1D9558C30934D19",
|
||||
"spki_sha256": "49DD353DC2B919A3770645117D0E60C16115E7D1BC259EEFE734B00EA434FE5F",
|
||||
"subject_key_identifier": "AE7E105C3C2996C1A847270559F1E03DD4E50AF3",
|
||||
"authority_key_identifier": "E13AAB217CF1E34D54AED472B7FD8B5942209054",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "ecdsa-with-SHA384",
|
||||
"not_before": "2025-04-30T15:35:09Z",
|
||||
"not_after": "2040-04-28T18:30:00Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-18T09:27:07Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.emsign.com/?roottlscag3.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDaDCCAu6gAwIBAgIPWIsuPCu4zaE+GhIJJUMhMAoGCCqGSM49BAMDMFYxCzAJ\nBgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk\nMSAwHgYDVQQDDBdlbVNpZ24gUm9vdCBUTFMgQ0EgLSBHMzAeFw0yNTA0MzAxNTM1\nMDlaFw00MDA0MjgxODMwMDBaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVk\naHJhIEluYzEbMBkGA1UEAwwSRU0gRFYgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0C\nAQYFK4EEACIDYgAEOnp4YsjETTJN3WkDOmeCwO/u/kBV5ooSP6A3G6O9kZRRTuFy\npDPjYw8CvRiAN9nlFJ+bd9uUooHfmHsv6oiLdL3+j9pMEJnubKGVZv4+8OX2sJpV\nbMyLpQVh3xsqRB0Bo4IBljCCAZIwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L\nWUIgkFQwHQYDVR0OBBYEFK5+EFw8KZbBqEcnBVnx4D3U5QrzMB0GA1UdJQQWMBQG\nCCsGAQUFBwMBBggrBgEFBQcDAjBdBgNVHSAEVjBUMDkGCysGAQQBg44hAQABMCow\nKAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB\nBAGDjiEBAmQwCAYGZ4EMAQIBMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY\naHR0cDovL29jc3AtYy5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw\nb3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNRFZUTFNDQUczQy5wN2MwNwYDVR0f\nBDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j\ncmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E\nAwMDaAAwZQIxAMEN2HWMocbuWdy1d33pH6JpMvP/V/DIS5PtZbv1Q7TXEbxrcyxg\nyuddOJscYDJJlAIwB4sH1BpbScDzkdD4tJBSwrG/1Mx82vb8YaySehNuu1+1oXNd\nAEKwaJ0mVzScy2+6\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM DV TLS CA - G3C",
|
||||
"usage": "tls",
|
||||
"issued_by": "AAA Certificate Services",
|
||||
"issuer_operator": "Sectigo",
|
||||
"issuer_sha256": "D7A7A0FB5D7E2731D771E9484EBCDEF71D5F0C3E0A2948782BC83EE0EA699EF4",
|
||||
"subject": "CN=EM DV TLS CA - G3C,O=eMudhra Inc,C=US",
|
||||
"issuer": "CN=AAA Certificate Services,O=Comodo CA Limited,L=Salford,ST=Greater Manchester,C=GB",
|
||||
"serial_hex": "91F347F1A5B7D39962B95E0EE4E299D1",
|
||||
"sha256": "62B7F9868263F72F6911FC78CEAF72C1979158B7368BF648683BB2AA39B02E72",
|
||||
"spki_sha256": "49DD353DC2B919A3770645117D0E60C16115E7D1BC259EEFE734B00EA434FE5F",
|
||||
"subject_key_identifier": "AE7E105C3C2996C1A847270559F1E03DD4E50AF3",
|
||||
"authority_key_identifier": "A0110A233E96F107ECE2AF29EF82A57FD030A4B4",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "sha256WithRSAEncryption",
|
||||
"not_before": "2025-05-14T00:00:00Z",
|
||||
"not_after": "2028-12-31T23:59:59Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-19T10:35:36Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.comodoca.com/AAACertificateServices.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDzzCCAregAwIBAgIRAJHzR/Glt9OZYrleDuTimdEwDQYJKoZIhvcNAQELBQAw\nezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV\nBAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNTA1MTQwMDAwMDBaFw0y\nODEyMzEyMzU5NTlaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVkaHJhIElu\nYzEbMBkGA1UEAwwSRU0gRFYgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0CAQYFK4EE\nACIDYgAEOnp4YsjETTJN3WkDOmeCwO/u/kBV5ooSP6A3G6O9kZRRTuFypDPjYw8C\nvRiAN9nlFJ+bd9uUooHfmHsv6oiLdL3+j9pMEJnubKGVZv4+8OX2sJpVbMyLpQVh\n3xsqRB0Bo4IBNTCCATEwHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQw\nHQYDVR0OBBYEFK5+EFw8KZbBqEcnBVnx4D3U5QrzMA4GA1UdDwEB/wQEAwIBBjAS\nBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD\nAjAxBgNVHSAEKjAoMAgGBmeBDAECATANBgsrBgEEAYOOIQEAATANBgsrBgEEAYOO\nIQECZDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9B\nQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA0BggrBgEFBQcBAQQoMCYwJAYIKwYB\nBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQsFAAOC\nAQEAr7b6Mx11TIJgVzHt6EH5qGNWeiiqoMrp8E5/k8s+jvupx1n083pZ5XOzUzND\nwEUe0W4C4FIGUHNQ4XDwqOw0yK42xqm2dvCKgsko2UvDlT0haZVtTCeWMQOe5J/J\nziaMfZwsZNfZ3aaI6XPtWDZtwY8AaNfyaeCpbtm5GcGnyNWk4jSNpbtpo6NjfXuP\nCFOm3rTjJ4zytP7Tso6iMm0L01cYFOlTmoPv4515R2r3SPnKDtijoB/D/vgxzojv\nDafgyG9afX8+laO9NbMMz4sqC1vZx3984i/sBNFiugm3Vvdq5OdJRjuGC1QILIs6\ndg/K3i8VQqRpbfaM9kIlMzZ3dQ==\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM OV TLS CA - G3C",
|
||||
"usage": "tls",
|
||||
"issued_by": "emSign Root TLS CA - G3",
|
||||
"issuer_operator": "eMudhra",
|
||||
"issuer_sha256": "7DD78D5F4F13459A83DFF9ABBBA62EDBAF6F2D102BF257FD712F4D9F2746ED8D",
|
||||
"subject": "CN=EM OV TLS CA - G3C,O=eMudhra Inc,C=US",
|
||||
"issuer": "CN=emSign Root TLS CA - G3,O=eMudhra Technologies Limited,C=IN",
|
||||
"serial_hex": "296926C227A3A1526392B19482A504",
|
||||
"sha256": "CB6E15165AC802E9B3F993F16C25D41F4E81C21EBDE71AE1B012AC00BF9C7C3F",
|
||||
"spki_sha256": "63ECEFEE431D49523BC1136C4E72D0206A477086CAF606CD5CF025686C109CF8",
|
||||
"subject_key_identifier": "34EAEA0CEBC90ADAF9D0C5E2ED9B78C9879E1B6C",
|
||||
"authority_key_identifier": "E13AAB217CF1E34D54AED472B7FD8B5942209054",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "ecdsa-with-SHA384",
|
||||
"not_before": "2025-04-30T15:37:41Z",
|
||||
"not_after": "2040-04-28T18:30:00Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-18T09:38:46Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.emsign.com/?roottlscag3.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDaDCCAu6gAwIBAgIPKWkmwiejoVJjkrGUgqUEMAoGCCqGSM49BAMDMFYxCzAJ\nBgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk\nMSAwHgYDVQQDDBdlbVNpZ24gUm9vdCBUTFMgQ0EgLSBHMzAeFw0yNTA0MzAxNTM3\nNDFaFw00MDA0MjgxODMwMDBaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVk\naHJhIEluYzEbMBkGA1UEAwwSRU0gT1YgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0C\nAQYFK4EEACIDYgAEE4JRzVKskpjByKrZdzId65fnCb0LTKCspV3IrVHc/J0ViaFZ\nfjpRIOHv1jHGPhg1ysrimGmmLhYx6KKBgatWYW3EXZGKvAnzqw5jz3kqpNztc4e+\nN7ulaVSfHAKycO1no4IBljCCAZIwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L\nWUIgkFQwHQYDVR0OBBYEFDTq6gzryQra+dDF4u2beMmHnhtsMB0GA1UdJQQWMBQG\nCCsGAQUFBwMBBggrBgEFBQcDAjBdBgNVHSAEVjBUMDkGCysGAQQBg44hAQABMCow\nKAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB\nBAGDjiEBAm4wCAYGZ4EMAQICMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY\naHR0cDovL29jc3AtYy5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw\nb3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNT1ZUTFNDQUczQy5wN2MwNwYDVR0f\nBDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j\ncmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E\nAwMDaAAwZQIxAMSZt2xsPeumRdeSMSQ3CbzIZeQ/q7GDCWfeE1Pq+mhgA6gRM44c\nNVF3xJ+wsxJk+wIwFJbaDMokD8Ei6eNOiA8yUMYvfzQyngmrhZQMdPCK1SewrR79\n4rSb9vGqxZzelQth\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM OV TLS CA - G3C",
|
||||
"usage": "tls",
|
||||
"issued_by": "AAA Certificate Services",
|
||||
"issuer_operator": "Sectigo",
|
||||
"issuer_sha256": "D7A7A0FB5D7E2731D771E9484EBCDEF71D5F0C3E0A2948782BC83EE0EA699EF4",
|
||||
"subject": "CN=EM OV TLS CA - G3C,O=eMudhra Inc,C=US",
|
||||
"issuer": "CN=AAA Certificate Services,O=Comodo CA Limited,L=Salford,ST=Greater Manchester,C=GB",
|
||||
"serial_hex": "8D5A4811939EF447D77111CDD9849AE9",
|
||||
"sha256": "7485B51C0ED192878FA1D2F948FB529AE1842CC5086C4B67F7BE5B2039DE9489",
|
||||
"spki_sha256": "63ECEFEE431D49523BC1136C4E72D0206A477086CAF606CD5CF025686C109CF8",
|
||||
"subject_key_identifier": "34EAEA0CEBC90ADAF9D0C5E2ED9B78C9879E1B6C",
|
||||
"authority_key_identifier": "A0110A233E96F107ECE2AF29EF82A57FD030A4B4",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "sha256WithRSAEncryption",
|
||||
"not_before": "2025-05-14T00:00:00Z",
|
||||
"not_after": "2028-12-31T23:59:59Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-19T10:35:36Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.comodoca.com/AAACertificateServices.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDzzCCAregAwIBAgIRAI1aSBGTnvRH13ERzdmEmukwDQYJKoZIhvcNAQELBQAw\nezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV\nBAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNTA1MTQwMDAwMDBaFw0y\nODEyMzEyMzU5NTlaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVkaHJhIElu\nYzEbMBkGA1UEAwwSRU0gT1YgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0CAQYFK4EE\nACIDYgAEE4JRzVKskpjByKrZdzId65fnCb0LTKCspV3IrVHc/J0ViaFZfjpRIOHv\n1jHGPhg1ysrimGmmLhYx6KKBgatWYW3EXZGKvAnzqw5jz3kqpNztc4e+N7ulaVSf\nHAKycO1no4IBNTCCATEwHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQw\nHQYDVR0OBBYEFDTq6gzryQra+dDF4u2beMmHnhtsMA4GA1UdDwEB/wQEAwIBBjAS\nBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD\nAjAxBgNVHSAEKjAoMAgGBmeBDAECAjANBgsrBgEEAYOOIQEAATANBgsrBgEEAYOO\nIQECbjBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9B\nQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA0BggrBgEFBQcBAQQoMCYwJAYIKwYB\nBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQsFAAOC\nAQEAHlbhZpjhkPEAQVhPHRtBDaHqiisVD20pQ1TUeSx3l62Qe7NQ0b7vWQy7DN0i\nKOu7BGpP5EnIjvXbz9FhpfPJ4FhKEt3tQ51rqXz2oD8vRaryvExWPobDUz3j7HN6\nOzBsVMIe3PD7AAkpky0x8zMSi/ep5R9OMzybmNptbtppyuB5ytgq+h7lQdRIP+CQ\nTaJX3qTgfMqzntYre5GljmEB5hU2/rSn8zoSU2APkJidlZFpghtgbD4I2VRHZvCw\nFFr/SrFM9pwrgbJNZ1MtyTSVgI5NlNb0aMfLR+/r6jJt3ROeY2yh2QQ2dx+Yqgdb\nuL5ChFWOQU+ErSDnUq7yr+pjBQ==\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM EV TLS CA - G3C",
|
||||
"usage": "tls",
|
||||
"issued_by": "emSign Root TLS CA - G3",
|
||||
"issuer_operator": "eMudhra",
|
||||
"issuer_sha256": "7DD78D5F4F13459A83DFF9ABBBA62EDBAF6F2D102BF257FD712F4D9F2746ED8D",
|
||||
"subject": "CN=EM EV TLS CA - G3C,O=eMudhra Inc,C=US",
|
||||
"issuer": "CN=emSign Root TLS CA - G3,O=eMudhra Technologies Limited,C=IN",
|
||||
"serial_hex": "8009928A64107601AF05FA2F19F109",
|
||||
"sha256": "432EC25F0D28DE9006D97BF752F17BBB2CD41F669933FCB072D9A1148D0261F3",
|
||||
"spki_sha256": "5C0660A2B164910D8FF589C18E14552E9E0EC237DCEFE2CB736D41A4811F81A0",
|
||||
"subject_key_identifier": "A6255E80A94DB7F3967C1BC791DF92BCEE4BEB5F",
|
||||
"authority_key_identifier": "E13AAB217CF1E34D54AED472B7FD8B5942209054",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "ecdsa-with-SHA384",
|
||||
"not_before": "2025-04-30T15:39:31Z",
|
||||
"not_after": "2040-04-28T18:30:00Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-18T09:30:49Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.emsign.com/?roottlscag3.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDaDCCAu6gAwIBAgIQAIAJkopkEHYBrwX6LxnxCTAKBggqhkjOPQQDAzBWMQsw\nCQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl\nZDEgMB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwHhcNMjUwNDMwMTUz\nOTMxWhcNNDAwNDI4MTgzMDAwWjBAMQswCQYDVQQGEwJVUzEUMBIGA1UECgwLZU11\nZGhyYSBJbmMxGzAZBgNVBAMMEkVNIEVWIFRMUyBDQSAtIEczQzB2MBAGByqGSM49\nAgEGBSuBBAAiA2IABC1W6Cmm+4LGSkaX2WCvlR6QZ66R+SbTQwbaSKiq63hptqZ+\nbSdCbgRCqgOzbhmI3/Y2UU7hzwf1uks/8qBmRa59MdWGatMao9JG6wsxd+6Zy3Vm\nxRbOdICKZo+R8MR/yqOCAZUwggGRMB8GA1UdIwQYMBaAFOE6qyF88eNNVK7Ucrf9\ni1lCIJBUMB0GA1UdDgQWBBSmJV6AqU2385Z8G8eR35K87kvrXzAdBgNVHSUEFjAU\nBggrBgEFBQcDAQYIKwYBBQUHAwIwXAYDVR0gBFUwUzA5BgsrBgEEAYOOIQEAATAq\nMCgGCCsGAQUFBwIBFhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMA0GCysG\nAQQBg44hAQJ4MAcGBWeBDAEBMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY\naHR0cDovL29jc3AtYy5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw\nb3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNRVZUTFNDQUczQy5wN2MwNwYDVR0f\nBDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j\ncmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E\nAwMDaAAwZQIwBy1wTnzH4lXDTy2PD91ysLjvnlVN3JbJmc1BIMEU8TOLkYVHibMc\n9HeyonikFSfmAjEA6uE3QRxlrZTz/1/lXPTEMUhoauAtycagtlNFp79kjhvNa2/f\nAal1GNxsOutLnr0Y\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM EV TLS CA - G3C",
|
||||
"usage": "tls",
|
||||
"issued_by": "AAA Certificate Services",
|
||||
"issuer_operator": "Sectigo",
|
||||
"issuer_sha256": "D7A7A0FB5D7E2731D771E9484EBCDEF71D5F0C3E0A2948782BC83EE0EA699EF4",
|
||||
"subject": "CN=EM EV TLS CA - G3C,O=eMudhra Inc,C=US",
|
||||
"issuer": "CN=AAA Certificate Services,O=Comodo CA Limited,L=Salford,ST=Greater Manchester,C=GB",
|
||||
"serial_hex": "05F078752DECE7A1BB8595D303167171",
|
||||
"sha256": "FD9D5C2DBBD4995AB69B8D50C439D9527B00529199C2FD01B2174EB58F07021F",
|
||||
"spki_sha256": "5C0660A2B164910D8FF589C18E14552E9E0EC237DCEFE2CB736D41A4811F81A0",
|
||||
"subject_key_identifier": "A6255E80A94DB7F3967C1BC791DF92BCEE4BEB5F",
|
||||
"authority_key_identifier": "A0110A233E96F107ECE2AF29EF82A57FD030A4B4",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "sha256WithRSAEncryption",
|
||||
"not_before": "2025-05-14T00:00:00Z",
|
||||
"not_after": "2028-12-31T23:59:59Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-19T10:35:36Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.comodoca.com/AAACertificateServices.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDzTCCArWgAwIBAgIQBfB4dS3s56G7hZXTAxZxcTANBgkqhkiG9w0BAQsFADB7\nMQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD\nVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE\nAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTI1MDUxNDAwMDAwMFoXDTI4\nMTIzMTIzNTk1OVowQDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC2VNdWRocmEgSW5j\nMRswGQYDVQQDDBJFTSBFViBUTFMgQ0EgLSBHM0MwdjAQBgcqhkjOPQIBBgUrgQQA\nIgNiAAQtVugppvuCxkpGl9lgr5UekGeukfkm00MG2kioqut4abamfm0nQm4EQqoD\ns24ZiN/2NlFO4c8H9bpLP/KgZkWufTHVhmrTGqPSRusLMXfumct1ZsUWznSAimaP\nkfDEf8qjggE0MIIBMDAfBgNVHSMEGDAWgBSgEQojPpbxB+zirynvgqV/0DCktDAd\nBgNVHQ4EFgQUpiVegKlNt/OWfBvHkd+SvO5L618wDgYDVR0PAQH/BAQDAgEGMBIG\nA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC\nMDAGA1UdIAQpMCcwBwYFZ4EMAQEwDQYLKwYBBAGDjiEBAAEwDQYLKwYBBAGDjiEB\nAngwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFB\nQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUF\nBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQELBQADggEB\nAIFfHiaMSjnrdZygRYV4ekRBmG7ybcFk4hGQWMMyMFi0cAEk2+dGfz5bl8IaIbLq\nz+uVJzhOgVEX7WqIfgbWfFsfPYHYjPHBmy7SlZ3BwA86IQ6qF/etpX2/qL9A5yRN\nN3nVowUpaqV6H3aCpkAh3wR2ZNkvAbLDvPz3J0l+sEWjWv+ZISOV4R+hXDTdPXV0\n1lKxnbwqEsdo/sE2QkCDKwFrZh/0uKjWspydJj+jSaDLTrGNx50Dgmn7VEcD1ZI5\nFXjknVUiO25YlmS1dtVZSBbyUKSjlrP/yDwPcZunoAsmCAAtCKsFLviLaymzvsKI\neSSDGxpSySp2VCxompGDk8g=\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM OV CS CA - G3B",
|
||||
"usage": "code-signing",
|
||||
"issued_by": "emSign Root CS CA - G3",
|
||||
"issuer_operator": "eMudhra",
|
||||
"issuer_sha256": "F2EDAAFF3D9B701FB4D14C9F285F8C0BAD90FC3BCC1FA07D47F4718EDABA34A5",
|
||||
"subject": "CN=EM OV CS CA - G3B,O=eMudhra BV,C=NL",
|
||||
"issuer": "CN=emSign Root CS CA - G3,O=eMudhra Technologies Limited,C=IN",
|
||||
"serial_hex": "7818933F8F85B4619A2B35FBA83D0A",
|
||||
"sha256": "9E39DE2881273ACC225A149C72BA3E0F51424963669AB633EE1DC7DF5DB067B4",
|
||||
"spki_sha256": "EC4FFA1AD0AC88081314B7AAFFEF6A91F97CD57291BB5BA686C5415F5EB4F6B6",
|
||||
"subject_key_identifier": "79FAE8ECCFDB0D758DA458D69FB6EDDC7C49DEE6",
|
||||
"authority_key_identifier": "687403F885CA8D5450571D16E0C8DE450DABCD2D",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "ecdsa-with-SHA384",
|
||||
"not_before": "2025-04-30T16:08:27Z",
|
||||
"not_after": "2040-04-28T18:30:00Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-18T09:33:37Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.emsign.com/?rootcscag3.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDWzCCAuCgAwIBAgIPeBiTP4+FtGGaKzX7qD0KMAoGCCqGSM49BAMDMFUxCzAJ\nBgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk\nMR8wHQYDVQQDDBZlbVNpZ24gUm9vdCBDUyBDQSAtIEczMB4XDTI1MDQzMDE2MDgy\nN1oXDTQwMDQyODE4MzAwMFowPjELMAkGA1UEBhMCTkwxEzARBgNVBAoMCmVNdWRo\ncmEgQlYxGjAYBgNVBAMMEUVNIE9WIENTIENBIC0gRzNCMHYwEAYHKoZIzj0CAQYF\nK4EEACIDYgAEqrsPsGZqz88B+tUr/P1MK/LLPDSX3nOVDlgZth/mlQmHQcjEkUOb\nNKBDHK/+W/m0wcjorgAB+fTcitgsWfNjnpbNbD1NsM7+wmw9YlF7N3YTcnQ/jord\nd7EAZPKr5eBQo4IBizCCAYcwHwYDVR0jBBgwFoAUaHQD+IXKjVRQVx0W4MjeRQ2r\nzS0wHQYDVR0OBBYEFHn66OzP2w11jaRY1p+27dx8Sd7mMBMGA1UdJQQMMAoGCCsG\nAQUFBwMDMF4GA1UdIARXMFUwOQYLKwYBBAGDjiEBAAEwKjAoBggrBgEFBQcCARYc\naHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbTAOBgwrBgEEAYOOIQECgUgwCAYG\nZ4EMAQQBMHQGCCsGAQUFBwEBBGgwZjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3At\nYi5lbXNpZ24uY29tMD4GCCsGAQUFBzAChjJodHRwOi8vcmVwb3NpdG9yeS5lbXNp\nZ24uY29tL2NlcnRzL0VNT1ZDU0NBRzNCLnA3YzA2BgNVHR8ELzAtMCugKaAnhiVo\ndHRwOi8vY3JsLmVtc2lnbi5jb20vP3Jvb3Rjc2NhZzMuY3JsMA4GA1UdDwEB/wQE\nAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMAoGCCqGSM49BAMDA2kAMGYCMQC/zr03\nYEELsNKqzUtH2dVFi4BaKFdyrr/6G1dIWp8KAVgsw2/u4lyyboUDaC9jDvICMQC9\nHTxku84tNX9dmHOtH7aC2Nu/JM0jTf6KjZAvovCJzzv1IFWSZpVLZibynMLXOrM=\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM OV CS CA - G3B",
|
||||
"usage": "code-signing",
|
||||
"issued_by": "AAA Certificate Services",
|
||||
"issuer_operator": "Sectigo",
|
||||
"issuer_sha256": "D7A7A0FB5D7E2731D771E9484EBCDEF71D5F0C3E0A2948782BC83EE0EA699EF4",
|
||||
"subject": "CN=EM OV CS CA - G3B,O=eMudhra BV,C=NL",
|
||||
"issuer": "CN=AAA Certificate Services,O=Comodo CA Limited,L=Salford,ST=Greater Manchester,C=GB",
|
||||
"serial_hex": "41E32B73AC185D6CE0D7480BACF84E69",
|
||||
"sha256": "A496E23AC0CAB8155FC9B117B97EAE368EFCBB9041AEC8804D5A308D2D01C2D8",
|
||||
"spki_sha256": "EC4FFA1AD0AC88081314B7AAFFEF6A91F97CD57291BB5BA686C5415F5EB4F6B6",
|
||||
"subject_key_identifier": "79FAE8ECCFDB0D758DA458D69FB6EDDC7C49DEE6",
|
||||
"authority_key_identifier": "A0110A233E96F107ECE2AF29EF82A57FD030A4B4",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "sha256WithRSAEncryption",
|
||||
"not_before": "2025-05-14T00:00:00Z",
|
||||
"not_after": "2028-12-31T23:59:59Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-19T10:35:36Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.comodoca.com/AAACertificateServices.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDwzCCAqugAwIBAgIQQeMrc6wYXWzg10gLrPhOaTANBgkqhkiG9w0BAQsFADB7\nMQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD\nVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE\nAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTI1MDUxNDAwMDAwMFoXDTI4\nMTIzMTIzNTk1OVowPjELMAkGA1UEBhMCTkwxEzARBgNVBAoMCmVNdWRocmEgQlYx\nGjAYBgNVBAMMEUVNIE9WIENTIENBIC0gRzNCMHYwEAYHKoZIzj0CAQYFK4EEACID\nYgAEqrsPsGZqz88B+tUr/P1MK/LLPDSX3nOVDlgZth/mlQmHQcjEkUObNKBDHK/+\nW/m0wcjorgAB+fTcitgsWfNjnpbNbD1NsM7+wmw9YlF7N3YTcnQ/jordd7EAZPKr\n5eBQo4IBLDCCASgwHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD\nVR0OBBYEFHn66OzP2w11jaRY1p+27dx8Sd7mMA4GA1UdDwEB/wQEAwIBBjASBgNV\nHRMBAf8ECDAGAQH/AgEAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMDIGA1UdIAQrMCkw\nCAYGZ4EMAQQBMA0GCysGAQQBg44hAQABMA4GDCsGAQQBg44hAQKBSDBDBgNVHR8E\nPDA6MDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9BQUFDZXJ0aWZpY2F0\nZVNlcnZpY2VzLmNybDA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6\nLy9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAIh0OzWsdBYhY\n7+yxPGyosRL+uUSN6/Mrd30fBuougs5FVWQ3cRgLhImnUUgXADY9buugWhMmfT3c\nyU5T1MFXZXClCILm5mfg+oqm/ikUWJl3Ayf2GvYf2O++6vzqvkn418nI5Lpdt0O7\nLi524YS/3CZHDA+zZQ7rrHpZXgQ9Hmp8AUQ4FneaGjNanFoYxiZxwCyW5z4u7AoK\n0bmOVqKtcDFoVNz5++G9TYDJdhWOXmKKgzqRo1MK0PjazNT7MGHqknP93SqMVJ1g\nmX/qNWxYteAjlvFanQxBNX/+TRxDjuFsEHO/7BvqSpIIck0UEEfizhN8zNpWLbcl\nEqVgl0g39A==\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM OV CS CA - G3C",
|
||||
"usage": "code-signing",
|
||||
"issued_by": "emSign Root CS CA - G3",
|
||||
"issuer_operator": "eMudhra",
|
||||
"issuer_sha256": "F2EDAAFF3D9B701FB4D14C9F285F8C0BAD90FC3BCC1FA07D47F4718EDABA34A5",
|
||||
"subject": "CN=EM OV CS CA - G3C,O=eMudhra Inc,C=US",
|
||||
"issuer": "CN=emSign Root CS CA - G3,O=eMudhra Technologies Limited,C=IN",
|
||||
"serial_hex": "544B7F922C31AE220A4A922916F6E6",
|
||||
"sha256": "4B2460A466F95FD40113BCDCCA2CEB29B3B093921DE45474DA7DF48874C630B1",
|
||||
"spki_sha256": "92C063D67E8F14DB71D288E11266FFDAF69CBF115F7BAB14F3BC2F68D25E0E30",
|
||||
"subject_key_identifier": "EE6F73298D6FBFA7B31BC39534F61556447866B7",
|
||||
"authority_key_identifier": "687403F885CA8D5450571D16E0C8DE450DABCD2D",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "ecdsa-with-SHA384",
|
||||
"not_before": "2025-04-30T16:38:40Z",
|
||||
"not_after": "2040-04-28T18:30:00Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-18T09:35:24Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.emsign.com/?rootcscag3.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDWzCCAuGgAwIBAgIPVEt/kiwxriIKSpIpFvbmMAoGCCqGSM49BAMDMFUxCzAJ\nBgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk\nMR8wHQYDVQQDDBZlbVNpZ24gUm9vdCBDUyBDQSAtIEczMB4XDTI1MDQzMDE2Mzg0\nMFoXDTQwMDQyODE4MzAwMFowPzELMAkGA1UEBhMCVVMxFDASBgNVBAoMC2VNdWRo\ncmEgSW5jMRowGAYDVQQDDBFFTSBPViBDUyBDQSAtIEczQzB2MBAGByqGSM49AgEG\nBSuBBAAiA2IABLnw4GNHAqacpqrdRDz9YsQbm6SyCSRpfXl052kaEm+5avs+NML9\nO8X0gwYfJl3CpYQ2NHMjUQQ2so8E84YjYwZ5gOJQPgJTLWVGI1pxZaJZoe9Jb3Qb\nX97neHII5Lj676OCAYswggGHMB8GA1UdIwQYMBaAFGh0A/iFyo1UUFcdFuDI3kUN\nq80tMB0GA1UdDgQWBBTub3MpjW+/p7Mbw5U09hVWRHhmtzATBgNVHSUEDDAKBggr\nBgEFBQcDAzBeBgNVHSAEVzBVMDkGCysGAQQBg44hAQABMCowKAYIKwYBBQUHAgEW\nHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDgYMKwYBBAGDjiEBAoFIMAgG\nBmeBDAEEATB0BggrBgEFBQcBAQRoMGYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3Nw\nLWMuZW1zaWduLmNvbTA+BggrBgEFBQcwAoYyaHR0cDovL3JlcG9zaXRvcnkuZW1z\naWduLmNvbS9jZXJ0cy9FTU9WQ1NDQUczQy5wN2MwNgYDVR0fBC8wLTAroCmgJ4Yl\naHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290Y3NjYWczLmNybDAOBgNVHQ8BAf8E\nBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAKBggqhkjOPQQDAwNoADBlAjEA8yPg\n8sntOhLwV2QXJ5LEaKSpo/fnE3uOgTadK73fDhyjiqr0Io9GVuQTYqBPbQ2TAjBg\neuApmBS486+iei03lRrp139dPw6k28jjGNvWsAU7A1N86J1zPJVDEyVH+nMAWC0=\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "EM OV CS CA - G3C",
|
||||
"usage": "code-signing",
|
||||
"issued_by": "AAA Certificate Services",
|
||||
"issuer_operator": "Sectigo",
|
||||
"issuer_sha256": "D7A7A0FB5D7E2731D771E9484EBCDEF71D5F0C3E0A2948782BC83EE0EA699EF4",
|
||||
"subject": "CN=EM OV CS CA - G3C,O=eMudhra Inc,C=US",
|
||||
"issuer": "CN=AAA Certificate Services,O=Comodo CA Limited,L=Salford,ST=Greater Manchester,C=GB",
|
||||
"serial_hex": "D6A5EF613B390F32EF9CDF349F772841",
|
||||
"sha256": "84112972B8E59D14560AE7E7119654474AAD119990CF3722BFC1E3B91615E1FD",
|
||||
"spki_sha256": "92C063D67E8F14DB71D288E11266FFDAF69CBF115F7BAB14F3BC2F68D25E0E30",
|
||||
"subject_key_identifier": "EE6F73298D6FBFA7B31BC39534F61556447866B7",
|
||||
"authority_key_identifier": "A0110A233E96F107ECE2AF29EF82A57FD030A4B4",
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "sha256WithRSAEncryption",
|
||||
"not_before": "2025-05-14T00:00:00Z",
|
||||
"not_after": "2028-12-31T23:59:59Z",
|
||||
"revocation": {
|
||||
"status": "revoked",
|
||||
"date": "2026-10-19T10:35:36Z",
|
||||
"reason": "ca_compromise",
|
||||
"crl_url": "http://crl.comodoca.com/AAACertificateServices.crl"
|
||||
},
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIDxTCCAq2gAwIBAgIRANal72E7OQ8y75zfNJ93KEEwDQYJKoZIhvcNAQELBQAw\nezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV\nBAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNTA1MTQwMDAwMDBaFw0y\nODEyMzEyMzU5NTlaMD8xCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVkaHJhIElu\nYzEaMBgGA1UEAwwRRU0gT1YgQ1MgQ0EgLSBHM0MwdjAQBgcqhkjOPQIBBgUrgQQA\nIgNiAAS58OBjRwKmnKaq3UQ8/WLEG5uksgkkaX15dOdpGhJvuWr7PjTC/TvF9IMG\nHyZdwqWENjRzI1EENrKPBPOGI2MGeYDiUD4CUy1lRiNacWWiWaHvSW90G1/e53hy\nCOS4+u+jggEsMIIBKDAfBgNVHSMEGDAWgBSgEQojPpbxB+zirynvgqV/0DCktDAd\nBgNVHQ4EFgQU7m9zKY1vv6ezG8OVNPYVVkR4ZrcwDgYDVR0PAQH/BAQDAgEGMBIG\nA1UdEwEB/wQIMAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwMgYDVR0gBCsw\nKTAIBgZngQwBBAEwDQYLKwYBBAGDjiEBAAEwDgYMKwYBBAGDjiEBAoFIMEMGA1Ud\nHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FBQUNlcnRpZmlj\nYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0\ncDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBgGbZ+NDkn\n2Fr5dCVs/51+6cT5iEPP1stglX4TI2UaNh9LmPdltxXw3crV8gK5L8i+d+ScGibF\ny0obtBHNTldXDgLnAHIzY3n+pceyKj7O2ae9CYnyuu5RBifeI3XYKowWE+oXnVGF\nOy0CvCJ/JsdP6aYgoCa9hGnAYicYQQL6MOMQZ5PuhcSM8t4giIzrpgrEkUP93GYE\nemDG5Z8BYwKs80lLeQNBnwg/VHJ3iEF/o84RXYwrlrKqJ+33C094o6LNikMJCqOK\n/WYHZSR8Xyhf8GXFAj5pZuI6Bcpug2V/E7i42j8OBhc25aNYDqK+B0qmb90sjNUB\ng3tJeSIb/599\n-----END CERTIFICATE-----"
|
||||
}
|
||||
]
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICPzCCAcagAwIBAgIUH0gWfBRnOiSjcduti/cukjDGAjIwCgYIKoZIzj0EAwIw
|
||||
PzELMAkGA1UEBhMCTkwxEzARBgNVBAoMCmVNdWRocmEgQlYxGzAZBgNVBAMMEkVN
|
||||
IE9WIFRMUyBDQSAtIEczQjAeFw0yNjEwMjAwMjIyNDJaFw0yNzA1MDMwMjI3NDJa
|
||||
MDMxMTAvBgNVBAMMKG92LWczYi1hYWEtZW11ZGhyYS53ZS1oYXZlLWEtcHJvYmxl
|
||||
bS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ3EfjVE+6fUm9gr7UoUv6N
|
||||
YPttIdILR9OMZnAdTj+RWT1Z4fp7dpC5mat1gbIo4J6EDelcOQQz5/oGeB3gFJKw
|
||||
o4GrMIGoMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
||||
CCsGAQUFBwMBMDMGA1UdEQQsMCqCKG92LWczYi1hYWEtZW11ZGhyYS53ZS1oYXZl
|
||||
LWEtcHJvYmxlbS5jb20wHQYDVR0OBBYEFKzQPp6gTBOWb0TBxZbkL5zsQn3oMB8G
|
||||
A1UdIwQYMBaAFJvYZVGv5+csN60I7mkZ2b83hK4KMAoGCCqGSM49BAMCA2cAMGQC
|
||||
MARKrRRBEWY2Ix1d80DGUvC7bWENP1Q9pf6BOGF4+84UiwV5+nAuht/+hdpAanWB
|
||||
sQIwJF2dW8tpPN6lTm1kDerzG6yJAJOz4drotaTthMF2+efuv5W2FL7Dr8qZSd1z
|
||||
201o
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDzjCCAragAwIBAgIRAOlCI73pL5FOWrmsq/2sNxAwDQYJKoZIhvcNAQELBQAw
|
||||
ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
|
||||
BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNTA1MTQwMDAwMDBaFw0y
|
||||
ODEyMzEyMzU5NTlaMD8xCzAJBgNVBAYTAk5MMRMwEQYDVQQKDAplTXVkaHJhIEJW
|
||||
MRswGQYDVQQDDBJFTSBPViBUTFMgQ0EgLSBHM0IwdjAQBgcqhkjOPQIBBgUrgQQA
|
||||
IgNiAARziXqg6zz9yosSQC/68KvE4SErr43ud4rJ7i1tuD+sKAxeBWOK56Ks1xwy
|
||||
Ko42HN659pxDArndjXPRzGyqsswK7k4hbOl53VGKSvS2JuVoTN1lgDftDIVOTMEv
|
||||
TPhkbQ2jggE1MIIBMTAfBgNVHSMEGDAWgBSgEQojPpbxB+zirynvgqV/0DCktDAd
|
||||
BgNVHQ4EFgQUm9hlUa/n5yw3rQjuaRnZvzeErgowDgYDVR0PAQH/BAQDAgEGMBIG
|
||||
A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
|
||||
MDEGA1UdIAQqMCgwCAYGZ4EMAQICMA0GCysGAQQBg44hAQABMA0GCysGAQQBg44h
|
||||
AQJuMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FB
|
||||
QUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEF
|
||||
BQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBCwUAA4IB
|
||||
AQALRoOSvkzRa+tN5Rje9W5GiXd/qsicd9N6Gnh0SWC7VyWH+HycIqAnFCMYZznj
|
||||
CeGusomFYHE42SHWr85JDIbgzy6y3dO4i9n9w0Bx7yrXWBbDzFS8VgA3+EY4Cg7y
|
||||
mtoC3RPOJVtaXXPZ+68X804g1Mj+3vCSHj2lNPVgco0OzSIOJ/KMg1R9MLBkiKzb
|
||||
bERAGZHejY0HBhYd76IINZN8z6bBNah2UdFYxsOisLynPQUkol6gRLum024/FzVl
|
||||
CCDfnUusrkr+mAfPAvD/Vb8bhpA7jYtepuU+2mIdShj5lLlvAwZphn+ypWycuo2x
|
||||
0k9mldz2dqI9nhCiY+TTIOOR
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,56 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICODCCAb6gAwIBAgIUPXjC97k7buQHZ7p5ehDU8QNyrR4wCgYIKoZIzj0EAwIw
|
||||
PzELMAkGA1UEBhMCTkwxEzARBgNVBAoMCmVNdWRocmEgQlYxGzAZBgNVBAMMEkVN
|
||||
IE9WIFRMUyBDQSAtIEczQjAeFw0yNjEwMjAwMDU5MzdaFw0yNzA1MDMwMTA0Mzda
|
||||
MC8xLTArBgNVBAMMJG92LWczYi1lbXVkaHJhLndlLWhhdmUtYS1wcm9ibGVtLmNv
|
||||
bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABA1haD+95Albk0UN6YtDCPpqevTv
|
||||
YUmEhsIVpb/hnhsbBlH0yLthSE2JLH14ywiQJXttoc/pDWC9eoICW6CJXL2jgacw
|
||||
gaQwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYB
|
||||
BQUHAwEwLwYDVR0RBCgwJoIkb3YtZzNiLWVtdWRocmEud2UtaGF2ZS1hLXByb2Js
|
||||
ZW0uY29tMB0GA1UdDgQWBBQUhzc4s202Hn62G0srmgguYdY2MTAfBgNVHSMEGDAW
|
||||
gBSb2GVRr+fnLDetCO5pGdm/N4SuCjAKBggqhkjOPQQDAgNoADBlAjEAoJ6d4zzA
|
||||
xE349yGHHrwKZpVCC/HBFutcOpOfzQoe8ikbmaaBTdtKai5TEllwt3dBAjBeHGiX
|
||||
VheDhJfewbei99cw1MfYB5tPwdfuY5pe1MJz0Tg9zJ4JgxBvF6LTT0OOXZ4=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDZjCCAu2gAwIBAgIPbK2jZ/scEACIEg6iAtVoMAoGCCqGSM49BAMDMFYxCzAJ
|
||||
BgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk
|
||||
MSAwHgYDVQQDDBdlbVNpZ24gUm9vdCBUTFMgQ0EgLSBHMzAeFw0yNTA0MzAxNjAw
|
||||
MTJaFw00MDA0MjgxODMwMDBaMD8xCzAJBgNVBAYTAk5MMRMwEQYDVQQKDAplTXVk
|
||||
aHJhIEJWMRswGQYDVQQDDBJFTSBPViBUTFMgQ0EgLSBHM0IwdjAQBgcqhkjOPQIB
|
||||
BgUrgQQAIgNiAARziXqg6zz9yosSQC/68KvE4SErr43ud4rJ7i1tuD+sKAxeBWOK
|
||||
56Ks1xwyKo42HN659pxDArndjXPRzGyqsswK7k4hbOl53VGKSvS2JuVoTN1lgDft
|
||||
DIVOTMEvTPhkbQ2jggGWMIIBkjAfBgNVHSMEGDAWgBThOqshfPHjTVSu1HK3/YtZ
|
||||
QiCQVDAdBgNVHQ4EFgQUm9hlUa/n5yw3rQjuaRnZvzeErgowHQYDVR0lBBYwFAYI
|
||||
KwYBBQUHAwEGCCsGAQUFBwMCMF0GA1UdIARWMFQwOQYLKwYBBAGDjiEBAAEwKjAo
|
||||
BggrBgEFBQcCARYcaHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbTANBgsrBgEE
|
||||
AYOOIQECbjAIBgZngQwBAgIwdQYIKwYBBQUHAQEEaTBnMCQGCCsGAQUFBzABhhho
|
||||
dHRwOi8vb2NzcC1iLmVtc2lnbi5jb20wPwYIKwYBBQUHMAKGM2h0dHA6Ly9yZXBv
|
||||
c2l0b3J5LmVtc2lnbi5jb20vY2VydHMvRU1PVlRMU0NBRzNCLnA3YzA3BgNVHR8E
|
||||
MDAuMCygKqAohiZodHRwOi8vY3JsLmVtc2lnbi5jb20vP3Jvb3R0bHNjYWczLmNy
|
||||
bDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAKBggqhkjOPQQD
|
||||
AwNnADBkAjBAk+5BizdJhrED3wb7F2Gm7bWI60dlNd075nghT2TrR4NWKZtJZcbc
|
||||
28xxIY/NONICMF6mPdsjosaqmvEMWqKcBh4vsIvXSKnQj5o8zrFB4oKS+accjYTe
|
||||
8Dz3bQjauvy9uw==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdDCCAvmgAwIBAgIQAJYaPvsTWVdu0EAFtGhKWzAKBggqhkjOPQQDAzBrMQsw
|
||||
CQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhy
|
||||
YSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290
|
||||
IENBIC0gRzMwHhcNMjQwNzExMTU0MzM2WhcNMzkwNzA5MTgzMDAwWjBWMQswCQYD
|
||||
VQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg
|
||||
MB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwdjAQBgcqhkjOPQIBBgUr
|
||||
gQQAIgNiAARfD9w/q1cWxL6D9bMGH6CQ4u+gAV6GN9s+PwQx9Bl4hC+0iU8QOk8m
|
||||
WO/RwXQy10DCSxT8vSIJClHKp+Ao4qJKdYeV0SwZ7LMQziyLfxIUOY6Grja/sQFw
|
||||
LKYf8EdDXAyjggF1MIIBcTAfBgNVHSMEGDAWgBR8XQKEE9TMipuBzhccLikenEhj
|
||||
QjAdBgNVHQ4EFgQU4TqrIXzx401UrtRyt/2LWUIgkFQwHQYDVR0lBBYwFAYIKwYB
|
||||
BQUHAwEGCCsGAQUFBwMCMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIB
|
||||
FhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMHgGCCsGAQUFBwEBBGwwajAi
|
||||
BggrBgEFBQcwAYYWaHR0cDovL29jc3AuZW1zaWduLmNvbTBEBggrBgEFBQcwAoY4
|
||||
aHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbS9jZXJ0cy9lbVNpZ25FQ0NSb290
|
||||
Q0FHMy5jcnQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbXNpZ24uY29t
|
||||
P1Jvb3RDQUczLmNybDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIB
|
||||
ATAKBggqhkjOPQQDAwNpADBmAjEAt9CIpRGp46QHQYDUBnLKw+vvK0/h9vmilEAg
|
||||
TroUl/anH4x2rXHqiCtBTBfgKDegAjEA8WpG1LTZdAIL0FSYqxXeREaeTSxEofM0
|
||||
1jJH3jGvCXC79LU9UPJ2o3TU+UIj2gMV
|
||||
-----END CERTIFICATE-----
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICQTCCAcegAwIBAgIULuWnWW6kFV6QZxp2ls8r18NCjXkwCgYIKoZIzj0EAwIw
|
||||
QDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC2VNdWRocmEgSW5jMRswGQYDVQQDDBJF
|
||||
TSBPViBUTFMgQ0EgLSBHM0MwHhcNMjYxMDIwMDIyMjQyWhcNMjcwNTAzMDIyNzQy
|
||||
WjAzMTEwLwYDVQQDDChvdi1nM2MtYWFhLWVtdWRocmEud2UtaGF2ZS1hLXByb2Js
|
||||
ZW0uY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEb7+5g2YHNYwH2eQERrZc
|
||||
TmVuf/RmvzsGGMSwXmZke6vn35Ut5HME7UOOU3Muy+BSfjfpo6fjL5KOs3Ndz67d
|
||||
OKOBqzCBqDAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAK
|
||||
BggrBgEFBQcDATAzBgNVHREELDAqgihvdi1nM2MtYWFhLWVtdWRocmEud2UtaGF2
|
||||
ZS1hLXByb2JsZW0uY29tMB0GA1UdDgQWBBQ7oBzq3jpTuvntbIkzMV12Ps3O0TAf
|
||||
BgNVHSMEGDAWgBQ06uoM68kK2vnQxeLtm3jJh54bbDAKBggqhkjOPQQDAgNoADBl
|
||||
AjEA/Y7AZ4M2MYbN5Od9tREaUfFjZKoOjczfIKPjKNMjtGxTdL9WUXvAT4QDgktn
|
||||
/IJdAjAbORTkAXD5hggyG6K7p0MBz3lFZJb2l/LndZlrttJWBLP8QGrc44hrZZtK
|
||||
Iq0d1dE=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDzzCCAregAwIBAgIRAI1aSBGTnvRH13ERzdmEmukwDQYJKoZIhvcNAQELBQAw
|
||||
ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
|
||||
BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNTA1MTQwMDAwMDBaFw0y
|
||||
ODEyMzEyMzU5NTlaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVkaHJhIElu
|
||||
YzEbMBkGA1UEAwwSRU0gT1YgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0CAQYFK4EE
|
||||
ACIDYgAEE4JRzVKskpjByKrZdzId65fnCb0LTKCspV3IrVHc/J0ViaFZfjpRIOHv
|
||||
1jHGPhg1ysrimGmmLhYx6KKBgatWYW3EXZGKvAnzqw5jz3kqpNztc4e+N7ulaVSf
|
||||
HAKycO1no4IBNTCCATEwHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQw
|
||||
HQYDVR0OBBYEFDTq6gzryQra+dDF4u2beMmHnhtsMA4GA1UdDwEB/wQEAwIBBjAS
|
||||
BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
|
||||
AjAxBgNVHSAEKjAoMAgGBmeBDAECAjANBgsrBgEEAYOOIQEAATANBgsrBgEEAYOO
|
||||
IQECbjBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9B
|
||||
QUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA0BggrBgEFBQcBAQQoMCYwJAYIKwYB
|
||||
BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQsFAAOC
|
||||
AQEAHlbhZpjhkPEAQVhPHRtBDaHqiisVD20pQ1TUeSx3l62Qe7NQ0b7vWQy7DN0i
|
||||
KOu7BGpP5EnIjvXbz9FhpfPJ4FhKEt3tQ51rqXz2oD8vRaryvExWPobDUz3j7HN6
|
||||
OzBsVMIe3PD7AAkpky0x8zMSi/ep5R9OMzybmNptbtppyuB5ytgq+h7lQdRIP+CQ
|
||||
TaJX3qTgfMqzntYre5GljmEB5hU2/rSn8zoSU2APkJidlZFpghtgbD4I2VRHZvCw
|
||||
FFr/SrFM9pwrgbJNZ1MtyTSVgI5NlNb0aMfLR+/r6jJt3ROeY2yh2QQ2dx+Yqgdb
|
||||
uL5ChFWOQU+ErSDnUq7yr+pjBQ==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,56 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICOTCCAb+gAwIBAgIUXcJ4+VeNEICJ9JbBANtIyfP96EowCgYIKoZIzj0EAwIw
|
||||
QDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC2VNdWRocmEgSW5jMRswGQYDVQQDDBJF
|
||||
TSBPViBUTFMgQ0EgLSBHM0MwHhcNMjYxMDIwMDA1OTM3WhcNMjcwNTAzMDEwNDM3
|
||||
WjAvMS0wKwYDVQQDDCRvdi1nM2MtZW11ZGhyYS53ZS1oYXZlLWEtcHJvYmxlbS5j
|
||||
b20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATLEvRHdoPc0Z9ovgqlYmoKTHPU
|
||||
Apwd6lAp0ou1G63SzuESyBzIW6Tl64CsKzlV9ggkZjX+L9/tOx97/1wmSTYvo4Gn
|
||||
MIGkMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsG
|
||||
AQUFBwMBMC8GA1UdEQQoMCaCJG92LWczYy1lbXVkaHJhLndlLWhhdmUtYS1wcm9i
|
||||
bGVtLmNvbTAdBgNVHQ4EFgQUrytBb+px+b58Df+d5vP8GpTW+/wwHwYDVR0jBBgw
|
||||
FoAUNOrqDOvJCtr50MXi7Zt4yYeeG2wwCgYIKoZIzj0EAwIDaAAwZQIwNdoOUOKz
|
||||
MLV1OFEoMjBeUqvkQAwsajvVWu0A23qyyvYlosyMp8aFv0gxURW6Yj6DAjEAhe0z
|
||||
kOQmmqb0eyhjh7weF4fHtwMtLi4jNFA6M/EfPTfkqE91MN9fSin5uhua5xhk
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDaDCCAu6gAwIBAgIPKWkmwiejoVJjkrGUgqUEMAoGCCqGSM49BAMDMFYxCzAJ
|
||||
BgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk
|
||||
MSAwHgYDVQQDDBdlbVNpZ24gUm9vdCBUTFMgQ0EgLSBHMzAeFw0yNTA0MzAxNTM3
|
||||
NDFaFw00MDA0MjgxODMwMDBaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVk
|
||||
aHJhIEluYzEbMBkGA1UEAwwSRU0gT1YgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0C
|
||||
AQYFK4EEACIDYgAEE4JRzVKskpjByKrZdzId65fnCb0LTKCspV3IrVHc/J0ViaFZ
|
||||
fjpRIOHv1jHGPhg1ysrimGmmLhYx6KKBgatWYW3EXZGKvAnzqw5jz3kqpNztc4e+
|
||||
N7ulaVSfHAKycO1no4IBljCCAZIwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L
|
||||
WUIgkFQwHQYDVR0OBBYEFDTq6gzryQra+dDF4u2beMmHnhtsMB0GA1UdJQQWMBQG
|
||||
CCsGAQUFBwMBBggrBgEFBQcDAjBdBgNVHSAEVjBUMDkGCysGAQQBg44hAQABMCow
|
||||
KAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB
|
||||
BAGDjiEBAm4wCAYGZ4EMAQICMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY
|
||||
aHR0cDovL29jc3AtYy5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw
|
||||
b3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNT1ZUTFNDQUczQy5wN2MwNwYDVR0f
|
||||
BDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j
|
||||
cmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E
|
||||
AwMDaAAwZQIxAMSZt2xsPeumRdeSMSQ3CbzIZeQ/q7GDCWfeE1Pq+mhgA6gRM44c
|
||||
NVF3xJ+wsxJk+wIwFJbaDMokD8Ei6eNOiA8yUMYvfzQyngmrhZQMdPCK1SewrR79
|
||||
4rSb9vGqxZzelQth
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdDCCAvmgAwIBAgIQAJYaPvsTWVdu0EAFtGhKWzAKBggqhkjOPQQDAzBrMQsw
|
||||
CQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhy
|
||||
YSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290
|
||||
IENBIC0gRzMwHhcNMjQwNzExMTU0MzM2WhcNMzkwNzA5MTgzMDAwWjBWMQswCQYD
|
||||
VQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg
|
||||
MB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwdjAQBgcqhkjOPQIBBgUr
|
||||
gQQAIgNiAARfD9w/q1cWxL6D9bMGH6CQ4u+gAV6GN9s+PwQx9Bl4hC+0iU8QOk8m
|
||||
WO/RwXQy10DCSxT8vSIJClHKp+Ao4qJKdYeV0SwZ7LMQziyLfxIUOY6Grja/sQFw
|
||||
LKYf8EdDXAyjggF1MIIBcTAfBgNVHSMEGDAWgBR8XQKEE9TMipuBzhccLikenEhj
|
||||
QjAdBgNVHQ4EFgQU4TqrIXzx401UrtRyt/2LWUIgkFQwHQYDVR0lBBYwFAYIKwYB
|
||||
BQUHAwEGCCsGAQUFBwMCMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIB
|
||||
FhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMHgGCCsGAQUFBwEBBGwwajAi
|
||||
BggrBgEFBQcwAYYWaHR0cDovL29jc3AuZW1zaWduLmNvbTBEBggrBgEFBQcwAoY4
|
||||
aHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbS9jZXJ0cy9lbVNpZ25FQ0NSb290
|
||||
Q0FHMy5jcnQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbXNpZ24uY29t
|
||||
P1Jvb3RDQUczLmNybDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIB
|
||||
ATAKBggqhkjOPQQDAwNpADBmAjEAt9CIpRGp46QHQYDUBnLKw+vvK0/h9vmilEAg
|
||||
TroUl/anH4x2rXHqiCtBTBfgKDegAjEA8WpG1LTZdAIL0FSYqxXeREaeTSxEofM0
|
||||
1jJH3jGvCXC79LU9UPJ2o3TU+UIj2gMV
|
||||
-----END CERTIFICATE-----
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
[
|
||||
{
|
||||
"name": "emSign Root TLS CA - G3",
|
||||
"operator": "eMudhra",
|
||||
"role": "direct_issuer",
|
||||
"subject": "CN=emSign Root TLS CA - G3,O=eMudhra Technologies Limited,C=IN",
|
||||
"serial_hex": "0E760672F143459FC8FE0AB0BC05E394",
|
||||
"sha256": "7DD78D5F4F13459A83DFF9ABBBA62EDBAF6F2D102BF257FD712F4D9F2746ED8D",
|
||||
"spki_sha256": "C619E4780ED8E0ABEDA24AD732567DE4383A7EA941338F6D1A7D1B49AC792FE9",
|
||||
"subject_key_identifier": "E13AAB217CF1E34D54AED472B7FD8B5942209054",
|
||||
"authority_key_identifier": null,
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "ecdsa-with-SHA384",
|
||||
"not_before": "2024-02-08T08:19:32Z",
|
||||
"not_after": "2049-02-07T08:19:32Z",
|
||||
"root_store_status": {
|
||||
"apple": "Not Included",
|
||||
"chrome": "Not Included",
|
||||
"microsoft": "Included",
|
||||
"mozilla": "Not Included"
|
||||
},
|
||||
"crl_url": "http://crl.emsign.com/?roottlscag3.crl",
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIICKTCCAa+gAwIBAgIQDnYGcvFDRZ/I/gqwvAXjlDAKBggqhkjOPQQDAzBWMQsw\nCQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl\nZDEgMB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwHhcNMjQwMjA4MDgx\nOTMyWhcNNDkwMjA3MDgxOTMyWjBWMQswCQYDVQQGEwJJTjElMCMGA1UECgwcZU11\nZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAwwXZW1TaWduIFJvb3Qg\nVExTIENBIC0gRzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARfD9w/q1cWxL6D9bMG\nH6CQ4u+gAV6GN9s+PwQx9Bl4hC+0iU8QOk8mWO/RwXQy10DCSxT8vSIJClHKp+Ao\n4qJKdYeV0SwZ7LMQziyLfxIUOY6Grja/sQFwLKYf8EdDXAyjQjBAMB0GA1UdDgQW\nBBThOqshfPHjTVSu1HK3/YtZQiCQVDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/\nBAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjBhCFTkly7Yl7+s4hiw+k6ZJTXT2AiI\nrvmsmfqPr5E7ecwXb6kXA5LTFd6rjwTuV3sCMQC9w6ZSbVq1mveMO6dKFziOzClT\nKCT2RFT6yXtq6nzgRICgBmiXbJAXsmZ8yAwjyWc=\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "emSign Root CS CA - G3",
|
||||
"operator": "eMudhra",
|
||||
"role": "direct_issuer",
|
||||
"subject": "CN=emSign Root CS CA - G3,O=eMudhra Technologies Limited,C=IN",
|
||||
"serial_hex": "018FCEC927C116F59C997EDC0CCD2E2B",
|
||||
"sha256": "F2EDAAFF3D9B701FB4D14C9F285F8C0BAD90FC3BCC1FA07D47F4718EDABA34A5",
|
||||
"spki_sha256": "0A6C2B2CA5B364207954171987AC9D2178561569D8205457E77CA90C32EDE282",
|
||||
"subject_key_identifier": "687403F885CA8D5450571D16E0C8DE450DABCD2D",
|
||||
"authority_key_identifier": null,
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "ecdsa-with-SHA384",
|
||||
"not_before": "2024-02-08T08:33:14Z",
|
||||
"not_after": "2049-02-07T08:33:14Z",
|
||||
"root_store_status": {
|
||||
"apple": "Not Included",
|
||||
"chrome": "Not Included",
|
||||
"microsoft": "Included",
|
||||
"mozilla": "Not Included"
|
||||
},
|
||||
"crl_url": "http://crl.emsign.com/?rootcscag3.crl",
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIICKDCCAa2gAwIBAgIQAY/OySfBFvWcmX7cDM0uKzAKBggqhkjOPQQDAzBVMQsw\nCQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl\nZDEfMB0GA1UEAwwWZW1TaWduIFJvb3QgQ1MgQ0EgLSBHMzAeFw0yNDAyMDgwODMz\nMTRaFw00OTAyMDcwODMzMTRaMFUxCzAJBgNVBAYTAklOMSUwIwYDVQQKDBxlTXVk\naHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMR8wHQYDVQQDDBZlbVNpZ24gUm9vdCBD\nUyBDQSAtIEczMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAESl9kM5D0VA/Og76dz5Xz\nw1hnGQ4fSR9993/qBkkvI48pXQVKOdyHCgAZThgWejQ8OpFRiTISjpabn4tfRFOY\nuzhApR/XxGbkg9X+2cEtbyghF9CdoF91W22V/R2EVe4xo0IwQDAdBgNVHQ4EFgQU\naHQD+IXKjVRQVx0W4MjeRQ2rzS0wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\nMAMBAf8wCgYIKoZIzj0EAwMDaQAwZgIxAK9OlACrFod3UgWY1ai+DF9sGFhahU59\nrv4jJyV01QaxGn0HErZ8gjHkngqe+tcFogIxAPTdW0hBmrGjhxBWdv9mZNdVFiJ4\nlrZ3ahvimsLhTQpnDBgiGKv6Ov1Fx/CE6yjIAg==\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "AAA Certificate Services",
|
||||
"operator": "Sectigo",
|
||||
"role": "direct_issuer",
|
||||
"subject": "CN=AAA Certificate Services,O=Comodo CA Limited,L=Salford,ST=Greater Manchester,C=GB",
|
||||
"serial_hex": "01",
|
||||
"sha256": "D7A7A0FB5D7E2731D771E9484EBCDEF71D5F0C3E0A2948782BC83EE0EA699EF4",
|
||||
"spki_sha256": "BD153ED7B0434F6886B17BCE8BBE84ED340C7132D702A8F4FA318F756ECBD6F3",
|
||||
"subject_key_identifier": "A0110A233E96F107ECE2AF29EF82A57FD030A4B4",
|
||||
"authority_key_identifier": null,
|
||||
"key": {
|
||||
"algorithm": "RSA",
|
||||
"bits": 2048
|
||||
},
|
||||
"signature_algorithm": "sha1WithRSAEncryption",
|
||||
"not_before": "2004-01-01T00:00:00Z",
|
||||
"not_after": "2028-12-31T23:59:59Z",
|
||||
"root_store_status": {
|
||||
"apple": "Included",
|
||||
"chrome": "Removed",
|
||||
"microsoft": "Included",
|
||||
"mozilla": "Removed"
|
||||
},
|
||||
"crl_url": "http://crl.comodoca.com/AAACertificateServices.crl",
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb\nMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow\nGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj\nYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL\nMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\nBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM\nGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP\nADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua\nBtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe\n3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4\nYgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR\nrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm\nez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU\noBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\nMAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v\nQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t\nb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF\nAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q\nGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz\nRt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2\nG9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi\nl2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3\nsmPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==\n-----END CERTIFICATE-----"
|
||||
},
|
||||
{
|
||||
"name": "emSign ECC Root CA - G3",
|
||||
"operator": "eMudhra",
|
||||
"role": "cross_signer",
|
||||
"subject": "CN=emSign ECC Root CA - G3,O=eMudhra Technologies Limited,OU=emSign PKI,C=IN",
|
||||
"serial_hex": "3CF607A968700EDA8B84",
|
||||
"sha256": "86A1ECBA089C4A8D3BBE2734C612BA341D813E043CF9E8A862CD5C57A36BBE6B",
|
||||
"spki_sha256": "8D417DB2DD8BF5E3084D1E3F196D583849D81BDD4C00C70B9D39369E96B8C782",
|
||||
"subject_key_identifier": "7C5D028413D4CC8A9B81CE171C2E291E9C486342",
|
||||
"authority_key_identifier": null,
|
||||
"key": {
|
||||
"algorithm": "EC",
|
||||
"curve": "secp384r1",
|
||||
"bits": 384
|
||||
},
|
||||
"signature_algorithm": "ecdsa-with-SHA384",
|
||||
"not_before": "2018-02-18T18:30:00Z",
|
||||
"not_after": "2043-02-18T18:30:00Z",
|
||||
"root_store_status": {
|
||||
"apple": "Included",
|
||||
"chrome": "Included",
|
||||
"microsoft": "Included",
|
||||
"mozilla": "Included"
|
||||
},
|
||||
"crl_url": "http://crl.emsign.com/?RootCAG3.crl",
|
||||
"pem": "-----BEGIN CERTIFICATE-----\nMIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG\nEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo\nbm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g\nRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ\nTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s\nb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw\ndjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0\nWXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS\nfvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB\nzhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq\nhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB\nCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD\n+JbNR6iC8hZVdyR+EhCVBCyj\n-----END CERTIFICATE-----"
|
||||
}
|
||||
]
|
||||
@@ -1,104 +0,0 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const { spawn } = require('node:child_process');
|
||||
const { once } = require('node:events');
|
||||
const fs = require('node:fs');
|
||||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
const { test } = require('node:test');
|
||||
|
||||
function archive(t, main, shell) {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'worker-startup-'));
|
||||
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
|
||||
const worker = path.join(root, 'packages/worker');
|
||||
fs.mkdirSync(path.join(worker, 'dist'), { recursive: true });
|
||||
fs.cpSync(path.join(__dirname, '../bin'), path.join(worker, 'bin'), { recursive: true });
|
||||
fs.writeFileSync(path.join(worker, 'dist/main.js'), main);
|
||||
if (shell) {
|
||||
fs.writeFileSync(path.join(worker, 'bin/start-worker.sh'), shell);
|
||||
}
|
||||
// Exercise the path that existing images run, including Node's symlink resolution.
|
||||
const legacy = path.join(root, 'src/services/worker/dist/main.js');
|
||||
fs.mkdirSync(path.dirname(legacy), { recursive: true });
|
||||
fs.symlinkSync('../../../../packages/worker/bin/bootstrap.cjs', legacy);
|
||||
return legacy;
|
||||
}
|
||||
|
||||
function launch(t, entry, args = []) {
|
||||
const child = spawn(process.execPath, [entry, ...args], {
|
||||
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
||||
env: { ...process.env, ENVIRONMENT: 'test' },
|
||||
});
|
||||
t.after(() => {
|
||||
if (child.exitCode === null && child.signalCode === null) {
|
||||
child.kill('SIGKILL');
|
||||
}
|
||||
});
|
||||
return child;
|
||||
}
|
||||
|
||||
test(
|
||||
'startup settings reach the worker before its first module runs',
|
||||
{ timeout: 10000 },
|
||||
async t => {
|
||||
const entry = archive(
|
||||
t,
|
||||
'process.send({ ready: true, args: process.argv.slice(2), setting: process.env.STARTUP_TEST }); process.on("message", () => process.exit(7));',
|
||||
'#!/bin/bash\nset -euo pipefail\nexport STARTUP_TEST=installed\nexec "$@"\n'
|
||||
);
|
||||
const child = launch(t, entry, ['argument with spaces']);
|
||||
const exited = once(child, 'exit');
|
||||
assert.deepEqual((await once(child, 'message'))[0], {
|
||||
ready: true,
|
||||
args: ['argument with spaces'],
|
||||
setting: 'installed',
|
||||
});
|
||||
child.send('stop');
|
||||
assert.deepEqual(await exited, [7, null]);
|
||||
}
|
||||
);
|
||||
|
||||
for (const signal of ['SIGINT', 'SIGTERM']) {
|
||||
test(`forwards ${signal} and preserves termination status`, { timeout: 10000 }, async t => {
|
||||
const entry = archive(t, 'process.send("ready"); setInterval(() => {}, 1000);');
|
||||
const child = launch(t, entry);
|
||||
const exited = once(child, 'exit');
|
||||
await once(child, 'message');
|
||||
child.kill(signal);
|
||||
assert.deepEqual(await exited, [null, signal]);
|
||||
});
|
||||
}
|
||||
|
||||
test('startup failure prevents loading the worker', { timeout: 10000 }, async t => {
|
||||
const entry = archive(
|
||||
t,
|
||||
'process.send("must not start");',
|
||||
'#!/bin/bash\nset -euo pipefail\nexit 42\nexec "$@"\n'
|
||||
);
|
||||
const child = launch(t, entry);
|
||||
const messages = [];
|
||||
child.on('message', message => messages.push(message));
|
||||
assert.deepEqual(await once(child, 'exit'), [42, null]);
|
||||
assert.deepEqual(messages, []);
|
||||
});
|
||||
|
||||
test('runs without IPC and retains stdout, stderr, and exit code', { timeout: 10000 }, async t => {
|
||||
const entry = archive(
|
||||
t,
|
||||
'console.log("worker output"); console.error("worker error"); process.exit(9);'
|
||||
);
|
||||
const child = spawn(process.execPath, [entry], {
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
env: { ...process.env, ENVIRONMENT: 'test' },
|
||||
});
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
child.stdout.on('data', data => {
|
||||
stdout += data;
|
||||
});
|
||||
child.stderr.on('data', data => {
|
||||
stderr += data;
|
||||
});
|
||||
assert.deepEqual(await once(child, 'close'), [9, null]);
|
||||
assert.equal(stdout, 'worker output\n');
|
||||
assert.equal(stderr, 'worker error\n');
|
||||
});
|
||||
@@ -1,201 +0,0 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const { spawn, execFileSync } = require('node:child_process');
|
||||
const { once } = require('node:events');
|
||||
const fs = require('node:fs');
|
||||
const https = require('node:https');
|
||||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
const { test } = require('node:test');
|
||||
|
||||
const tlsDirectory = path.join(__dirname, '../bin/tls');
|
||||
const fixtures = path.join(__dirname, 'fixtures/tls');
|
||||
|
||||
function temporary(t) {
|
||||
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'worker-tls-'));
|
||||
t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
|
||||
return directory;
|
||||
}
|
||||
|
||||
function verify(bundle, chain) {
|
||||
return execFileSync(
|
||||
'openssl',
|
||||
[
|
||||
'verify',
|
||||
'-no_check_time',
|
||||
'-no-CApath',
|
||||
'-no-CAstore',
|
||||
'-CAfile',
|
||||
bundle,
|
||||
'-untrusted',
|
||||
chain,
|
||||
chain,
|
||||
],
|
||||
{ stdio: 'pipe' }
|
||||
);
|
||||
}
|
||||
|
||||
test('rejects all 12 published affected chains after replacing trust', t => {
|
||||
const directory = temporary(t);
|
||||
const baseline = path.join(directory, 'before.pem');
|
||||
const roots = JSON.parse(fs.readFileSync(path.join(fixtures, 'roots.json')));
|
||||
fs.writeFileSync(baseline, roots.map(root => root.pem).join('\n'));
|
||||
const chains = fs.readdirSync(fixtures).filter(name => name.endsWith('.pem'));
|
||||
assert.equal(chains.length, 12);
|
||||
for (const name of chains) {
|
||||
const chain = path.join(fixtures, name);
|
||||
verify(baseline, chain);
|
||||
assert.throws(
|
||||
() => verify(path.join(tlsDirectory, 'ca.pem'), chain),
|
||||
error =>
|
||||
error.status !== 0 && /unable to get local issuer certificate/.test(String(error.stderr))
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('preserves Java entries and backups, and stops on an unsupported blocklist', t => {
|
||||
const directory = temporary(t);
|
||||
const original = `Algorithm=SHA-256\n${'A'.repeat(64)}`;
|
||||
const paths = [
|
||||
'jdk17/lib/security/blocked.certs',
|
||||
'jdk8/jre/lib/security/blacklisted.certs',
|
||||
'jdk17.jdk/Contents/Home/lib/security/blocked.certs',
|
||||
'jdk8.jdk/Contents/Home/jre/lib/security/blacklisted.certs',
|
||||
].map(relative => path.join(directory, relative));
|
||||
for (const blocklist of paths) {
|
||||
fs.mkdirSync(path.dirname(blocklist), { recursive: true });
|
||||
fs.writeFileSync(blocklist, original);
|
||||
}
|
||||
const script = path.join(tlsDirectory, 'block-java-certificates.sh');
|
||||
execFileSync('/bin/bash', [script, directory]);
|
||||
const first = paths.map(blocklist => fs.readFileSync(blocklist, 'utf8'));
|
||||
for (const [index, blocklist] of paths.entries()) {
|
||||
assert.equal(fs.readFileSync(`${blocklist}.before-eas-tls-policy`, 'utf8'), original);
|
||||
assert.ok(first[index].startsWith(`${original}\n`));
|
||||
assert.ok(
|
||||
first[index].includes('42C4ACCD12C4F59597925E1A08A7A90102608543809308D50EC427E118BA1493\n')
|
||||
);
|
||||
}
|
||||
execFileSync('/bin/bash', [script, directory]);
|
||||
assert.deepEqual(
|
||||
paths.map(blocklist => fs.readFileSync(blocklist, 'utf8')),
|
||||
first
|
||||
);
|
||||
fs.writeFileSync(paths[0], 'Algorithm=SHA-1\n');
|
||||
assert.throws(
|
||||
() => execFileSync('/bin/bash', [script, directory], { stdio: 'pipe' }),
|
||||
error => /Unsupported Java blocklist/.test(String(error.stderr))
|
||||
);
|
||||
});
|
||||
|
||||
test(
|
||||
'the packaged worker uses the CA bundle at Node startup and stops on setup failure',
|
||||
{ timeout: 20000 },
|
||||
async t => {
|
||||
const directory = temporary(t);
|
||||
const worker = path.join(directory, 'packages/worker');
|
||||
fs.cpSync(path.join(__dirname, '../bin'), path.join(worker, 'bin'), { recursive: true });
|
||||
fs.mkdirSync(path.join(worker, 'dist'));
|
||||
const entry = path.join(directory, 'src/services/worker/dist/main.js');
|
||||
fs.mkdirSync(path.dirname(entry), { recursive: true });
|
||||
fs.symlinkSync('../../../../packages/worker/bin/bootstrap.cjs', entry);
|
||||
const certificate = path.join(directory, 'local.pem');
|
||||
const key = path.join(directory, 'local.key');
|
||||
execFileSync(
|
||||
'openssl',
|
||||
[
|
||||
'req',
|
||||
'-x509',
|
||||
'-newkey',
|
||||
'rsa:2048',
|
||||
'-nodes',
|
||||
'-days',
|
||||
'1',
|
||||
'-subj',
|
||||
'/CN=localhost',
|
||||
'-addext',
|
||||
'subjectAltName=IP:127.0.0.1',
|
||||
'-keyout',
|
||||
key,
|
||||
'-out',
|
||||
certificate,
|
||||
],
|
||||
{ stdio: 'pipe' }
|
||||
);
|
||||
const caPath = path.join(worker, 'bin/tls/ca.pem');
|
||||
fs.appendFileSync(caPath, fs.readFileSync(certificate));
|
||||
const server = https.createServer(
|
||||
{ key: fs.readFileSync(key), cert: fs.readFileSync(certificate) },
|
||||
(_request, response) => response.end('trusted')
|
||||
);
|
||||
t.after(() => server.close());
|
||||
server.listen(0, '127.0.0.1');
|
||||
await once(server, 'listening');
|
||||
|
||||
// Do not change the test host's JDKs or invoke real sudo. Java writes have their own test above.
|
||||
const javaHook = path.join(worker, 'bin/tls/block-java-certificates.sh');
|
||||
fs.writeFileSync(javaHook, '#!/bin/bash\nexit 0\n');
|
||||
const commands = path.join(directory, 'commands');
|
||||
fs.mkdirSync(commands);
|
||||
fs.writeFileSync(
|
||||
path.join(commands, 'sudo'),
|
||||
'#!/bin/bash\n[ "$1" = -n ] || exit 90\nshift\nexec "$@"\n',
|
||||
{ mode: 0o755 }
|
||||
);
|
||||
const loaded = path.join(directory, 'worker-loaded');
|
||||
fs.writeFileSync(
|
||||
path.join(worker, 'dist/main.js'),
|
||||
`
|
||||
require('node:fs').writeFileSync(${JSON.stringify(loaded)}, 'yes');
|
||||
require('node:https').get('https://127.0.0.1:${server.address().port}', response => {
|
||||
response.resume(); response.on('end', () => {
|
||||
console.log(JSON.stringify({ file: process.env.SSL_CERT_FILE, options: process.env.NODE_OPTIONS }));
|
||||
});
|
||||
}).on('error', error => { console.error(error.code); process.exitCode = 1; });
|
||||
`
|
||||
);
|
||||
async function runAsync(extra = {}) {
|
||||
const child = spawn(process.execPath, [entry], {
|
||||
env: {
|
||||
...process.env,
|
||||
ENVIRONMENT: 'staging',
|
||||
NODE_OPTIONS: '--max-old-space-size=512',
|
||||
NODE_EXTRA_CA_CERTS: '',
|
||||
PATH: `${commands}:${process.env.PATH}`,
|
||||
...extra,
|
||||
},
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
});
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
child.stdout.on('data', data => {
|
||||
stdout += data;
|
||||
});
|
||||
child.stderr.on('data', data => {
|
||||
stderr += data;
|
||||
});
|
||||
const [code] = await once(child, 'close');
|
||||
return { code, stdout, stderr };
|
||||
}
|
||||
const success = await runAsync();
|
||||
assert.equal(success.code, 0, success.stderr);
|
||||
assert.deepEqual(JSON.parse(success.stdout), {
|
||||
file: fs.realpathSync(caPath),
|
||||
options: '--max-old-space-size=512 --use-openssl-ca',
|
||||
});
|
||||
// The same endpoint must fail when its independent test CA is removed.
|
||||
fs.copyFileSync(path.join(tlsDirectory, 'ca.pem'), caPath);
|
||||
const denied = await runAsync();
|
||||
assert.equal(denied.code, 1);
|
||||
assert.match(denied.stderr, /DEPTH_ZERO_SELF_SIGNED_CERT/);
|
||||
|
||||
fs.rmSync(loaded);
|
||||
const conflict = await runAsync({ NODE_OPTIONS: '--use-bundled-ca' });
|
||||
assert.notEqual(conflict.code, 0);
|
||||
assert.match(conflict.stderr, /Conflicting Node CA options/);
|
||||
assert.equal(fs.existsSync(loaded), false);
|
||||
fs.writeFileSync(javaHook, '#!/bin/bash\nexit 41\n');
|
||||
const failure = await runAsync();
|
||||
assert.equal(failure.code, 41);
|
||||
assert.equal(fs.existsSync(loaded), false);
|
||||
}
|
||||
);
|
||||
Reference in new issue
Block a user