rpki/ui/rpki-explorer/tests/e2e/fixtures.ts

492 lines
13 KiB
TypeScript

/**
* Deterministic fixture dataset for the mocked query service.
* Object types use the report-stream vocabulary (manifest / certificate / aspa).
*/
export const RUN_2 = {
schemaVersion: 1,
runId: "run_0002",
runSeq: 2,
validationTime: "2026-07-16T23:55:00Z",
syncMode: "delta",
wallMs: 732000,
artifactPaths: {
"report.json": "/data/runs/run_0002/report.json",
"run-summary.json": "/data/runs/run_0002/run-summary.json",
},
counts: {
publicationPoints: 4,
objects: 1284,
rejectedObjects: 2,
warnings: 3,
trustAnchors: 5,
vrps: 987,
aspas: 12,
},
indexStatus: "ready",
};
export const RUN_1 = {
...RUN_2,
runId: "run_0001",
runSeq: 1,
validationTime: "2026-07-15T23:50:00Z",
syncMode: "snapshot",
wallMs: 1290000,
artifactPaths: {
"report.json": "/data/runs/run_0001/report.json",
"run-summary.json": "/data/runs/run_0001/run-summary.json",
},
counts: { ...RUN_2.counts, objects: 1270, vrps: 981 },
};
export const RUNS = [RUN_2, RUN_1];
export const REPO_A = {
repoId: "repo-a1b2c3d4e5f6",
uri: "rsync://repo-a.example/ca1/",
host: "repo-a.example",
transport: "rrdp",
publicationPoints: 2,
objects: 900,
rejectedObjects: 1,
downloadBytes: 245_000_000,
syncDurationMsTotal: 12_400,
phases: { rrdp_snapshot: 1, rrdp_delta: 1 },
terminalStates: { fresh: 2 },
};
export const REPO_B = {
repoId: "repo-b2c3d4e5f6a7",
uri: "rsync://repo-b.example/ca2/",
host: "repo-b.example",
transport: "rsync",
publicationPoints: 1,
objects: 300,
rejectedObjects: 1,
downloadBytes: 80_000_000,
syncDurationMsTotal: 45_800,
phases: { rsync: 1 },
terminalStates: { cached: 1 },
};
export const REPO_C = {
repoId: "repo-c3d4e5f6a7b8",
uri: "rsync://repo-c.example/ca3/",
host: "repo-c.example",
transport: "rrdp",
publicationPoints: 1,
objects: 84,
rejectedObjects: 0,
downloadBytes: 9_000_000,
syncDurationMsTotal: 3_100,
phases: { rrdp_delta: 1 },
terminalStates: { fresh: 1 },
};
export const REPOS = [REPO_A, REPO_B, REPO_C];
export const PP_1 = {
ppId: "node_1",
repoId: REPO_A.repoId,
nodeId: 1,
rsyncBaseUri: "rsync://repo-a.example/ca1/",
manifestRsyncUri: "rsync://repo-a.example/ca1/manifest.mft",
publicationPointRsyncUri: "rsync://repo-a.example/ca1/",
rrdpNotificationUri: "https://repo-a.example/notification.xml",
source: "rrdp",
repoSyncSource: "rrdp",
repoSyncPhase: "rrdp_delta",
repoSyncDurationMs: 1200,
repoSyncError: null,
repoTerminalState: "fresh",
thisUpdate: "2026-07-16T23:00:00Z",
nextUpdate: "2026-07-17T23:00:00Z",
objects: 610,
rejectedObjects: 1,
warnings: 2,
};
export const PP_2 = {
...PP_1,
ppId: "node_2",
nodeId: 2,
manifestRsyncUri: "rsync://repo-a.example/ca1b/manifest.mft",
publicationPointRsyncUri: "rsync://repo-a.example/ca1b/",
objects: 290,
rejectedObjects: 0,
warnings: 1,
};
export const PP_3 = {
...PP_1,
ppId: "node_3",
nodeId: 3,
repoId: REPO_B.repoId,
manifestRsyncUri: "rsync://repo-b.example/ca2/manifest.mft",
publicationPointRsyncUri: "rsync://repo-b.example/ca2/",
rrdpNotificationUri: null,
source: "rsync",
repoSyncSource: "rsync",
repoSyncPhase: "rsync",
repoTerminalState: "cached",
objects: 300,
rejectedObjects: 1,
warnings: 0,
};
export const PPS = [PP_1, PP_2, PP_3];
const SHA = (ch: string) => ch.repeat(64);
export const OBJ_ROA = {
objectInstanceId: "obj-roa-0001",
uri: "rsync://repo-a.example/ca1/alice.roa",
sha256: SHA("a"),
objectType: "roa",
result: "ok",
detailSummary: null,
repoId: REPO_A.repoId,
ppId: PP_1.ppId,
sourceSection: "fresh",
rejected: false,
rejectReason: null,
};
export const OBJ_MFT = {
objectInstanceId: "obj-mft-0001",
uri: "rsync://repo-a.example/ca1/manifest.mft",
sha256: SHA("b"),
objectType: "manifest",
result: "ok",
detailSummary: null,
repoId: REPO_A.repoId,
ppId: PP_1.ppId,
sourceSection: "fresh",
rejected: false,
rejectReason: null,
};
export const OBJ_CER_REJECTED = {
objectInstanceId: "obj-cer-0001",
uri: "rsync://repo-a.example/ca1/stale.cer",
sha256: SHA("c"),
objectType: "certificate",
result: "error",
detailSummary: "certificate expired: notAfter 2026-01-01T00:00:00Z",
repoId: REPO_A.repoId,
ppId: PP_1.ppId,
sourceSection: "cached",
rejected: true,
rejectReason: "certificate expired: notAfter 2026-01-01T00:00:00Z",
};
export const OBJ_ASPA = {
objectInstanceId: "obj-asa-0001",
uri: "rsync://repo-b.example/ca2/bob.asa",
sha256: SHA("d"),
objectType: "aspa",
result: "ok",
detailSummary: null,
repoId: REPO_B.repoId,
ppId: PP_3.ppId,
sourceSection: "cached",
rejected: false,
rejectReason: null,
};
export const OBJ_ROA_REJECTED = {
objectInstanceId: "obj-roa-0002",
uri: "rsync://repo-b.example/ca2/broken.roa",
sha256: SHA("e"),
objectType: "roa",
result: "error",
detailSummary: "manifest stale: thisUpdate in the past",
repoId: REPO_B.repoId,
ppId: PP_3.ppId,
sourceSection: "cached",
rejected: true,
rejectReason: "manifest stale: thisUpdate in the past",
};
export const OBJ_CRL = {
objectInstanceId: "obj-crl-0001",
uri: "rsync://repo-a.example/ca1/main.crl",
sha256: SHA("f"),
objectType: "crl",
result: "ok",
detailSummary: null,
repoId: REPO_A.repoId,
ppId: PP_1.ppId,
sourceSection: "fresh",
rejected: false,
rejectReason: null,
};
export const OBJECTS = [OBJ_ROA, OBJ_MFT, OBJ_CER_REJECTED, OBJ_ASPA, OBJ_ROA_REJECTED, OBJ_CRL];
export const STATS_VALIDATION = { ok: 1279, error: 2, skipped: 3 };
export const STATS_OBJECT_TYPES = {
roa: 640,
manifest: 4,
crl: 4,
certificate: 620,
aspa: 12,
gbr: 4,
};
export const STATS_REASONS = {
"certificate expired: notAfter 2026-01-01T00:00:00Z": 1,
"manifest stale: thisUpdate in the past": 1,
};
export const ROA_PROJECTION = {
schemaVersion: 2,
sha256: SHA("a"),
objectType: "roa",
parseStatus: "ok",
// Mirrors the live query service shape:
// projection = { input, object: { type, roa|manifest|… }, schemaVersion, tool }
projection: {
input: {
type: "roa",
path: "rsync://repo-a.example/ca1/alice.roa",
bytes: { len: 1280, sha256: SHA("a") },
},
object: {
type: "roa",
roa: {
asId: 65001,
ipAddressFamilies: [
{
afi: "ipv4",
addresses: [
{ prefix: "203.0.113.0/24", maxLength: 24 },
{ prefix: "198.51.100.0/25", maxLength: 25 },
],
},
{
afi: "ipv6",
addresses: [{ prefix: "2001:db8::/32", maxLength: 48 }],
},
],
},
},
schemaVersion: 2,
tool: "rpki",
},
};
export const MFT_PROJECTION = {
schemaVersion: 2,
sha256: SHA("b"),
objectType: "mft",
parseStatus: "ok",
projection: {
input: {
type: "mft",
path: "rsync://repo-a.example/ca1/manifest.mft",
bytes: { len: 2048, sha256: SHA("b") },
},
object: {
type: "mft",
manifest: {
manifestNumberHex: "0A2F",
thisUpdate: "2026-07-16T23:00:00Z",
nextUpdate: "2026-07-17T23:00:00Z",
fileHashAlg: "sha256",
fileCount: 3,
},
},
schemaVersion: 2,
tool: "rpki",
},
};
export const MFT_FILES = [
{ fileName: "alice.roa", hashHex: SHA("a") },
{ fileName: "manifest.mft", hashHex: SHA("b") },
{ fileName: "stale.cer", hashHex: SHA("c") },
];
// Certificate projection in the real nested API shape:
// certificate payload under `object.resourceCertificate`, SKI/AKI/SIA/AIA/CRLDP
// and IP/AS resources under `extensions`.
export const CER_PROJECTION = {
schemaVersion: 2,
sha256: SHA("c"),
objectType: "cer",
parseStatus: "ok",
projection: {
input: {
type: "cer",
path: "rsync://repo-a.example/ca1/stale.cer",
bytes: { len: 1534, sha256: SHA("c") },
},
object: {
type: "cer",
decode: { profileValid: true },
resourceCertificate: {
kind: "Ca",
version: 3,
serialNumberHex: "02C6C7",
issuer: "CN=A90DC5BE, serialNumber=0E65A4F5",
subject: "CN=A9114E750000, serialNumber=5A179648",
validity: { notBefore: "2026-07-23T00:30:06Z", notAfter: "2027-09-30T00:00:00Z" },
signatureAlgorithm: "1.2.840.113549.1.1.11",
extensions: {
subjectKeyIdentifier: "5a179648b3ef2369dce7bdb58140ff7dc7060abf",
authorityKeyIdentifier: "0e65a4f5fd36b5bd68eb3c923408978c907aa79f",
basicConstraintsCa: true,
subjectInfoAccess: {
accessDescriptions: [
{ accessMethodOid: "1.3.6.1.5.5.7.48.5", accessLocation: "rsync://repo-a.example/ca1/" },
],
},
caIssuersUris: ["rsync://repo-a.example/ca1/issuer.cer"],
crlDistributionPointsUris: ["rsync://repo-a.example/ca1/main.crl"],
ipResources: {
families: [
{
afi: "Ipv4",
choice: {
AddressesOrRanges: [
{ Prefix: { addr: [103, 152, 34, 0], afi: "Ipv4", prefix_len: 23 } },
{ Range: { min: { addr: [192, 0, 2, 0] }, max: { addr: [192, 0, 2, 255] } } },
],
},
},
{
afi: "Ipv6",
choice: {
AddressesOrRanges: [
{
Prefix: {
addr: [38, 6, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
afi: "Ipv6",
prefix_len: 32,
},
},
],
},
},
],
},
asResources: {
asnum: {
AsIdsOrRanges: [{ Id: 38008 }, { Id: 38023 }, { Range: { min: 65536, max: 65551 } }],
},
},
},
},
},
schemaVersion: 2,
tool: "rpki",
},
};
// CRL projection in the real nested API shape: CRL fields sit directly on the
// typed payload (no `crl` wrapper); crlNumber/AKI live under `extensions`.
export const CRL_PROJECTION = {
schemaVersion: 2,
sha256: SHA("f"),
objectType: "crl",
parseStatus: "ok",
projection: {
input: {
type: "crl",
path: "rsync://repo-a.example/ca1/main.crl",
bytes: { len: 900, sha256: SHA("f") },
},
object: {
type: "crl",
decode: { profileValid: true },
issuer: "CN=A9114E750000, serialNumber=5A179648",
thisUpdate: "2026-07-23T02:47:00Z",
nextUpdate: "2026-07-24T02:52:00Z",
signatureAlgorithm: "1.2.840.113549.1.1.11",
extensions: {
authorityKeyIdentifier: "5a179648b3ef2369dce7bdb58140ff7dc7060abf",
crlNumber: 3394,
crlNumberHex: "0D42",
},
revokedCertificates: {
count: 2,
entries: [
{ serialNumberHex: "1B0B0AD86D78E77D1491B5069E6287D08EEA7C17", revocationDate: "2027-02-13T13:22:01Z" },
{ serialNumberHex: "6A106263F88133615B7E8D3466C192CEC0904F2D", revocationDate: "2027-03-18T19:58:00Z" },
],
},
},
schemaVersion: 2,
tool: "rpki",
},
};
export const CRL_REVOKED = [
{ serialNumberHex: "1B0B0AD86D78E77D1491B5069E6287D08EEA7C17", revocationDate: "2027-02-13T13:22:01Z" },
{ serialNumberHex: "6A106263F88133615B7E8D3466C192CEC0904F2D", revocationDate: "2027-03-18T19:58:00Z" },
];
export const VALIDATION_SUMMARY = {
finalStatus: "valid",
auditResult: "ok",
detailSummary: null,
parsevalidate: { status: "ok", issues: [] },
chainvalidate: { status: "ok", issues: [] },
};
export const EXPLAIN_RECORD = {
finalStatus: "valid",
auditResult: "ok",
authoritative: false,
explainMode: "audit_projection",
parsevalidate: { status: "ok", issues: [] },
chainvalidate: { status: "ok", mode: "audit_projection", issues: [], edgesCount: 2 },
chainEdges: [],
};
export const CHAIN_EDGES = [
{
relation: "issued_by",
fromUri: "rsync://repo-a.example/ca1/alice.roa",
toUri: "rsync://repo-a.example/ca1/ca-certificate.cer",
toObjectInstanceId: "obj-cer-0002",
toSha256: SHA("f"),
status: "linked",
},
{
relation: "listed_in",
fromUri: "rsync://repo-a.example/ca1/alice.roa",
toUri: "rsync://repo-a.example/ca1/manifest.mft",
toObjectInstanceId: "obj-mft-0001",
toSha256: SHA("b"),
status: "linked",
},
];
export const HEALTH = {
status: "ok",
service: "rpki_query_service",
version: 1,
latestReadyRun: "run_0002",
};
export const SERVICE_INFO = { service: "rpki_query_service", version: 1 };
/**
* VRP lookup fixtures (backend feature #122). 61 rows match `ip=81.68.1.1`
* so the UI's 50-row page size paginates; the /16 row exercises covering
* semantics for prefix queries, the IPv6 row exercises the second family.
*/
export const VRPS = [
{ runId: "run_0002", asn: 45090, prefix: "81.68.0.0/14", maxLength: 14 },
{ runId: "run_0002", asn: 64496, prefix: "81.68.0.0/16", maxLength: 24 },
...Array.from({ length: 59 }, (_, i) => ({
runId: "run_0002",
asn: 64512 + i,
prefix: "81.68.0.0/14",
maxLength: 14,
})),
{ runId: "run_0002", asn: 0, prefix: "2001:7fa:0:1::/64", maxLength: 64 },
];