test: add runtime boundary guard
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
# HWLAB Runtime Boundary Guard
|
||||
|
||||
The HWLAB runtime may use UniDesk CI/CD infrastructure and Code Queue
|
||||
scheduling, but it must not use UniDesk backend, provider-gateway, or
|
||||
microservice proxy as replacement runtime services. Those systems are external
|
||||
supporting infrastructure only.
|
||||
|
||||
This guard is intentionally static. It reads repository files and does not
|
||||
contact the DEV endpoint, deploy to DEV or PROD, read secrets, or restart any
|
||||
UniDesk or HWLAB runtime process.
|
||||
|
||||
## Boundary Rule
|
||||
|
||||
- HWLAB runtime service identity is the frozen `hwlab-*` service ID set.
|
||||
- DEV is the only accepted runtime environment for this guard.
|
||||
- The fixed DEV endpoint is `http://74.48.78.17:6667`.
|
||||
- The DEV namespace is `hwlab-dev`.
|
||||
- PROD deployment and PROD acceptance remain disabled.
|
||||
- UniDesk backend, provider-gateway, and microservice proxy are forbidden
|
||||
runtime substitutes.
|
||||
|
||||
UniDesk may remain in the control-plane path for CI, CD, and Code Queue
|
||||
scheduling. It must not terminate HWLAB health, API, gateway, router, tunnel,
|
||||
agent, simulator, patch-panel, CLI, or skills runtime contracts on behalf of
|
||||
HWLAB.
|
||||
|
||||
## Checked Artifacts
|
||||
|
||||
The machine-readable fixture is
|
||||
`protocol/examples/runtime-boundary/guard.dev.json`. It records the expected
|
||||
DEV-only boundary, frozen service IDs, forbidden substitutes, and paths checked
|
||||
by `scripts/validate-runtime-boundary.mjs`.
|
||||
|
||||
The validator checks:
|
||||
|
||||
- `deploy/deploy.json` keeps `environment: dev`, `hwlab-dev`, the fixed DEV
|
||||
endpoint, the complete HWLAB service set, HWLAB image names, and a disabled
|
||||
PROD profile.
|
||||
- `deploy/master-edge/health-contract.json` keeps the `frp` D601-to-master
|
||||
reverse link, HWLAB contract service IDs, and the forbidden substitute list.
|
||||
- `deploy/k8s/base/workloads.yaml` keeps workload names, labels, container
|
||||
names, and images under HWLAB service IDs.
|
||||
- `deploy/k8s/base/services.yaml` keeps Kubernetes service names and labels
|
||||
under HWLAB service IDs.
|
||||
- `deploy/k8s/dev/*` keeps the DEV overlay and runtime substitute policy.
|
||||
- `deploy/k8s/prod/*` keeps PROD as a disabled placeholder only.
|
||||
|
||||
## Validation
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
node --check scripts/validate-runtime-boundary.mjs
|
||||
node scripts/validate-runtime-boundary.mjs
|
||||
```
|
||||
|
||||
The script is lightweight and has no package dependency. It fails if a checked
|
||||
artifact drifts toward a UniDesk runtime substitute, a non-DEV environment, an
|
||||
unexpected namespace, an unexpected endpoint, or an incomplete HWLAB service
|
||||
boundary.
|
||||
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"guard": "hwlab-runtime-boundary",
|
||||
"schemaVersion": "v1",
|
||||
"environment": "dev",
|
||||
"endpoint": "http://74.48.78.17:6667",
|
||||
"namespace": "hwlab-dev",
|
||||
"scope": "static-runtime-boundary",
|
||||
"policy": {
|
||||
"runtimeSubstitution": "forbidden",
|
||||
"prodDeployment": "forbidden",
|
||||
"realDevDeployment": "out_of_scope",
|
||||
"allowedUniDeskRoles": ["ci", "cd", "code_queue_scheduling"],
|
||||
"forbiddenRuntimeSubstitutes": [
|
||||
"unidesk-backend",
|
||||
"provider-gateway",
|
||||
"microservice-proxy"
|
||||
]
|
||||
},
|
||||
"requiredManifest": {
|
||||
"path": "deploy/deploy.json",
|
||||
"environment": "dev",
|
||||
"namespace": "hwlab-dev",
|
||||
"prodProfileEnabled": false,
|
||||
"requiredServiceIds": [
|
||||
"hwlab-cloud-api",
|
||||
"hwlab-cloud-web",
|
||||
"hwlab-agent-mgr",
|
||||
"hwlab-agent-worker",
|
||||
"hwlab-gateway",
|
||||
"hwlab-gateway-simu",
|
||||
"hwlab-box-simu",
|
||||
"hwlab-patch-panel",
|
||||
"hwlab-router",
|
||||
"hwlab-tunnel-client",
|
||||
"hwlab-edge-proxy",
|
||||
"hwlab-cli",
|
||||
"hwlab-agent-skills"
|
||||
]
|
||||
},
|
||||
"requiredHealthContract": {
|
||||
"path": "deploy/master-edge/health-contract.json",
|
||||
"reverseLink": {
|
||||
"mode": "frp",
|
||||
"direction": "d601-to-master",
|
||||
"client": "hwlab-tunnel-client"
|
||||
},
|
||||
"requiredContractServiceIds": [
|
||||
"hwlab-edge-proxy",
|
||||
"hwlab-router",
|
||||
"hwlab-tunnel-client",
|
||||
"hwlab-cloud-api",
|
||||
"hwlab-cloud-web",
|
||||
"hwlab-agent-mgr",
|
||||
"hwlab-agent-worker",
|
||||
"hwlab-gateway-simu",
|
||||
"hwlab-box-simu",
|
||||
"hwlab-patch-panel"
|
||||
]
|
||||
},
|
||||
"requiredK3sSkeleton": {
|
||||
"workloadsPath": "deploy/k8s/base/workloads.yaml",
|
||||
"servicesPath": "deploy/k8s/base/services.yaml",
|
||||
"devKustomizationPath": "deploy/k8s/dev/kustomization.yaml",
|
||||
"devHealthContractPath": "deploy/k8s/dev/health-contract.yaml",
|
||||
"prodKustomizationPath": "deploy/k8s/prod/kustomization.yaml",
|
||||
"prodDisabledPath": "deploy/k8s/prod/prod-disabled.yaml",
|
||||
"requiredWorkloadServiceIds": [
|
||||
"hwlab-cloud-api",
|
||||
"hwlab-cloud-web",
|
||||
"hwlab-agent-mgr",
|
||||
"hwlab-agent-worker",
|
||||
"hwlab-gateway",
|
||||
"hwlab-gateway-simu",
|
||||
"hwlab-box-simu",
|
||||
"hwlab-patch-panel",
|
||||
"hwlab-router",
|
||||
"hwlab-tunnel-client",
|
||||
"hwlab-edge-proxy",
|
||||
"hwlab-cli",
|
||||
"hwlab-agent-skills"
|
||||
],
|
||||
"requiredServiceServiceIds": [
|
||||
"hwlab-cloud-api",
|
||||
"hwlab-cloud-web",
|
||||
"hwlab-gateway",
|
||||
"hwlab-cli",
|
||||
"hwlab-agent-skills",
|
||||
"hwlab-agent-mgr",
|
||||
"hwlab-gateway-simu",
|
||||
"hwlab-box-simu",
|
||||
"hwlab-patch-panel",
|
||||
"hwlab-router",
|
||||
"hwlab-tunnel-client",
|
||||
"hwlab-edge-proxy"
|
||||
]
|
||||
},
|
||||
"validation": {
|
||||
"script": "scripts/validate-runtime-boundary.mjs",
|
||||
"commands": [
|
||||
"node --check scripts/validate-runtime-boundary.mjs",
|
||||
"node scripts/validate-runtime-boundary.mjs"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
#!/usr/bin/env node
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { DEV_ENDPOINT, ENVIRONMENT_DEV, SERVICE_IDS } from "../internal/protocol/index.mjs";
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const serviceIdLabel = "hwlab.pikastech.local/service-id";
|
||||
const namespace = "hwlab-dev";
|
||||
const forbiddenRuntimeSubstitutes = Object.freeze([
|
||||
"unidesk-backend",
|
||||
"provider-gateway",
|
||||
"microservice-proxy"
|
||||
]);
|
||||
|
||||
async function readText(relativePath) {
|
||||
return readFile(path.join(repoRoot, relativePath), "utf8");
|
||||
}
|
||||
|
||||
async function readJSON(relativePath) {
|
||||
const raw = await readText(relativePath);
|
||||
return JSON.parse(raw);
|
||||
}
|
||||
|
||||
function assertObject(value, label) {
|
||||
assert.ok(value && typeof value === "object" && !Array.isArray(value), `${label} must be an object`);
|
||||
}
|
||||
|
||||
function assertArray(value, label) {
|
||||
assert.ok(Array.isArray(value), `${label} must be an array`);
|
||||
}
|
||||
|
||||
function assertUnique(values, label) {
|
||||
assert.equal(new Set(values).size, values.length, `${label} must be unique`);
|
||||
}
|
||||
|
||||
function assertSameMembers(actual, expected, label) {
|
||||
assert.deepEqual([...actual].sort(), [...expected].sort(), `${label} must match expected members`);
|
||||
}
|
||||
|
||||
function assertServiceId(serviceId, label) {
|
||||
assert.ok(SERVICE_IDS.includes(serviceId), `${label} uses unknown serviceId ${JSON.stringify(serviceId)}`);
|
||||
assert.match(serviceId, /^hwlab-/, `${label} must be an HWLAB service id`);
|
||||
assertNoForbiddenSubstitute(serviceId, label);
|
||||
}
|
||||
|
||||
function assertDevOnlyEnvironment(value, label) {
|
||||
assert.equal(value, ENVIRONMENT_DEV, `${label} must be dev`);
|
||||
}
|
||||
|
||||
function assertDevNamespace(value, label) {
|
||||
assert.equal(value, namespace, `${label} must be ${namespace}`);
|
||||
}
|
||||
|
||||
function assertForbiddenList(actual, label) {
|
||||
assertArray(actual, label);
|
||||
assertSameMembers(actual, forbiddenRuntimeSubstitutes, label);
|
||||
}
|
||||
|
||||
function splitCsv(value) {
|
||||
assert.equal(typeof value, "string", "CSV value must be a string");
|
||||
return value
|
||||
.split(",")
|
||||
.map((item) => item.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function assertNoForbiddenSubstitute(value, label) {
|
||||
if (typeof value !== "string") {
|
||||
return;
|
||||
}
|
||||
const lower = value.toLowerCase();
|
||||
for (const forbidden of forbiddenRuntimeSubstitutes) {
|
||||
assert.equal(
|
||||
lower.includes(forbidden),
|
||||
false,
|
||||
`${label} must not use forbidden runtime substitute ${forbidden}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function assertNoForbiddenSubstitutesDeep(value, label) {
|
||||
if (
|
||||
label.endsWith(".HWLAB_RUNTIME_SUBSTITUTE_FORBIDDEN") ||
|
||||
label.endsWith(".forbiddenRuntimeSubstitutes")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof value === "string") {
|
||||
assertNoForbiddenSubstitute(value, label);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((item, index) => assertNoForbiddenSubstitutesDeep(item, `${label}[${index}]`));
|
||||
return;
|
||||
}
|
||||
|
||||
if (value && typeof value === "object") {
|
||||
if (value.name === "HWLAB_RUNTIME_SUBSTITUTE_FORBIDDEN") {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const [key, item] of Object.entries(value)) {
|
||||
assertNoForbiddenSubstitutesDeep(item, `${label}.${key}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function containerList(workload, label) {
|
||||
const template = workload.kind === "Job" ? workload.spec?.template : workload.spec?.template;
|
||||
const containers = template?.spec?.containers;
|
||||
assertArray(containers, `${label}.containers`);
|
||||
return containers;
|
||||
}
|
||||
|
||||
function labelsFor(resource, label) {
|
||||
const labels = resource.metadata?.labels;
|
||||
assertObject(labels, `${label}.metadata.labels`);
|
||||
return labels;
|
||||
}
|
||||
|
||||
function assertMetadataServiceId(resource, expectedServiceId, label) {
|
||||
assert.equal(resource.metadata?.name, expectedServiceId, `${label}.metadata.name must match service id`);
|
||||
assertDevNamespace(resource.metadata?.namespace, `${label}.metadata.namespace`);
|
||||
const labels = labelsFor(resource, label);
|
||||
assert.equal(labels[serviceIdLabel], expectedServiceId, `${label} service-id label`);
|
||||
assert.equal(labels["app.kubernetes.io/name"], expectedServiceId, `${label} app name label`);
|
||||
}
|
||||
|
||||
function assertTemplateServiceId(workload, expectedServiceId, label) {
|
||||
const templateLabels = workload.spec?.template?.metadata?.labels;
|
||||
assertObject(templateLabels, `${label}.spec.template.metadata.labels`);
|
||||
assert.equal(templateLabels[serviceIdLabel], expectedServiceId, `${label} template service-id label`);
|
||||
assert.equal(templateLabels["app.kubernetes.io/name"], expectedServiceId, `${label} template app name label`);
|
||||
}
|
||||
|
||||
function assertHwlabImage(image, serviceId, label) {
|
||||
assert.equal(
|
||||
typeof image,
|
||||
"string",
|
||||
`${label}.image must be a string`
|
||||
);
|
||||
assert.match(
|
||||
image,
|
||||
new RegExp(`^ghcr\\.io/pikastech/${serviceId}:[a-f0-9]{7,40}$`),
|
||||
`${label}.image must be the HWLAB image for ${serviceId}`
|
||||
);
|
||||
}
|
||||
|
||||
function assertHealthProbe(container, serviceId, label) {
|
||||
if (serviceId === "hwlab-agent-worker" || serviceId === "hwlab-cli") {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const probeName of ["readinessProbe", "livenessProbe"]) {
|
||||
assert.equal(
|
||||
container[probeName]?.httpGet?.path,
|
||||
"/health/live",
|
||||
`${label}.${probeName} must use /health/live`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function assertNoExternalNameSubstitute(service, label) {
|
||||
assert.notEqual(service.spec?.type, "ExternalName", `${label} must not be an ExternalName substitute`);
|
||||
assert.equal(service.spec?.type, "ClusterIP", `${label} must be a ClusterIP skeleton service`);
|
||||
}
|
||||
|
||||
function assertKustomizationDevOnly(kustomization, label) {
|
||||
assert.equal(kustomization.kind, "Kustomization", `${label}.kind`);
|
||||
assertDevNamespace(kustomization.namespace, `${label}.namespace`);
|
||||
assert.equal(kustomization.commonLabels?.["hwlab.pikastech.local/profile"], "dev", `${label} profile label`);
|
||||
assert.ok(kustomization.resources?.includes("../base"), `${label} must include ../base`);
|
||||
}
|
||||
|
||||
function assertRuntimePolicyText(value, label) {
|
||||
assert.equal(typeof value, "string", `${label} must be a string`);
|
||||
assert.ok(value.includes("HWLAB runtime"), `${label} must name HWLAB runtime`);
|
||||
assert.ok(value.includes("UniDesk backend"), `${label} must name UniDesk backend`);
|
||||
assert.ok(value.includes("provider-gateway"), `${label} must name provider-gateway`);
|
||||
assert.ok(value.includes("microservice proxy"), `${label} must name microservice proxy`);
|
||||
}
|
||||
|
||||
function assertGuardFixture(guard) {
|
||||
assert.equal(guard.guard, "hwlab-runtime-boundary");
|
||||
assert.equal(guard.schemaVersion, "v1");
|
||||
assertDevOnlyEnvironment(guard.environment, "guard.environment");
|
||||
assert.equal(guard.endpoint, DEV_ENDPOINT, "guard.endpoint");
|
||||
assertDevNamespace(guard.namespace, "guard.namespace");
|
||||
assert.equal(guard.policy?.runtimeSubstitution, "forbidden", "guard runtime substitution policy");
|
||||
assert.equal(guard.policy?.prodDeployment, "forbidden", "guard prod policy");
|
||||
assertForbiddenList(guard.policy?.forbiddenRuntimeSubstitutes, "guard forbidden substitutes");
|
||||
assertSameMembers(guard.requiredManifest?.requiredServiceIds, SERVICE_IDS, "guard manifest service ids");
|
||||
assertSameMembers(guard.requiredK3sSkeleton?.requiredWorkloadServiceIds, SERVICE_IDS, "guard workload service ids");
|
||||
assert.ok(
|
||||
guard.validation?.commands?.includes("node scripts/validate-runtime-boundary.mjs"),
|
||||
"guard must record executable validation command"
|
||||
);
|
||||
}
|
||||
|
||||
function assertDeployManifest(manifest, guard) {
|
||||
assert.equal(manifest.manifestVersion, "v1");
|
||||
assertDevOnlyEnvironment(manifest.environment, "deploy manifest environment");
|
||||
assertDevNamespace(manifest.namespace, "deploy manifest namespace");
|
||||
assert.equal(manifest.endpoint, DEV_ENDPOINT, "deploy manifest endpoint");
|
||||
assert.ok(manifest.profiles?.dev?.enabled, "deploy manifest dev profile must be enabled");
|
||||
assertDevNamespace(manifest.profiles.dev.namespace, "deploy manifest dev profile namespace");
|
||||
assert.equal(manifest.profiles.dev.endpoint, DEV_ENDPOINT, "deploy manifest dev profile endpoint");
|
||||
assert.equal(manifest.profiles?.prod?.enabled, false, "deploy manifest prod profile must stay disabled");
|
||||
|
||||
assertArray(manifest.services, "deploy manifest services");
|
||||
const serviceIds = manifest.services.map((service) => service.serviceId);
|
||||
assertUnique(serviceIds, "deploy manifest service ids");
|
||||
assertSameMembers(serviceIds, guard.requiredManifest.requiredServiceIds, "deploy manifest service ids");
|
||||
assertSameMembers(serviceIds, SERVICE_IDS, "deploy manifest service ids");
|
||||
|
||||
for (const service of manifest.services) {
|
||||
assertServiceId(service.serviceId, `deploy service ${service.serviceId}`);
|
||||
assertHwlabImage(service.image, service.serviceId, `deploy service ${service.serviceId}`);
|
||||
assertDevNamespace(service.namespace, `${service.serviceId}.namespace`);
|
||||
assert.equal(service.profile, "dev", `${service.serviceId}.profile must be dev`);
|
||||
assert.match(service.healthPath, /^\//, `${service.serviceId}.healthPath must be absolute`);
|
||||
assertNoForbiddenSubstitutesDeep(service.env ?? {}, `${service.serviceId}.env`);
|
||||
}
|
||||
|
||||
const cloudApi = manifest.services.find((service) => service.serviceId === "hwlab-cloud-api");
|
||||
assertForbiddenList(
|
||||
splitCsv(cloudApi?.env?.HWLAB_RUNTIME_SUBSTITUTE_FORBIDDEN),
|
||||
"hwlab-cloud-api HWLAB_RUNTIME_SUBSTITUTE_FORBIDDEN"
|
||||
);
|
||||
}
|
||||
|
||||
function assertMasterHealthContract(contract, guard) {
|
||||
assertDevOnlyEnvironment(contract.environment, "master health contract environment");
|
||||
assert.equal(contract.endpoint, DEV_ENDPOINT, "master health contract endpoint");
|
||||
assert.equal(contract.prodAcceptance, false, "master health contract prodAcceptance");
|
||||
assert.equal(contract.reverseLink?.mode, guard.requiredHealthContract.reverseLink.mode, "reverse link mode");
|
||||
assert.equal(
|
||||
contract.reverseLink?.direction,
|
||||
guard.requiredHealthContract.reverseLink.direction,
|
||||
"reverse link direction"
|
||||
);
|
||||
assert.equal(contract.reverseLink?.client, "hwlab-tunnel-client", "reverse link client");
|
||||
assert.equal(contract.reverseLink?.publicPort, 6667, "reverse link public port");
|
||||
assertForbiddenList(contract.forbiddenRuntimeSubstitutes, "master forbidden substitutes");
|
||||
|
||||
assertArray(contract.contracts, "master health contracts");
|
||||
const serviceIds = contract.contracts.map((item) => item.serviceId);
|
||||
assertUnique(serviceIds, "master health contract service ids");
|
||||
assertSameMembers(
|
||||
serviceIds,
|
||||
guard.requiredHealthContract.requiredContractServiceIds,
|
||||
"master health contract service ids"
|
||||
);
|
||||
for (const item of contract.contracts) {
|
||||
assertServiceId(item.serviceId, `master health contract ${item.serviceId}`);
|
||||
}
|
||||
}
|
||||
|
||||
function assertWorkloads(workloads, guard) {
|
||||
assert.equal(workloads.kind, "List", "workloads kind");
|
||||
assertArray(workloads.items, "workloads items");
|
||||
|
||||
const serviceIds = workloads.items.map((item) => item.metadata?.labels?.[serviceIdLabel]);
|
||||
assertUnique(serviceIds, "workload service ids");
|
||||
assertSameMembers(serviceIds, guard.requiredK3sSkeleton.requiredWorkloadServiceIds, "workload service ids");
|
||||
|
||||
for (const workload of workloads.items) {
|
||||
const serviceId = workload.metadata?.labels?.[serviceIdLabel];
|
||||
assertServiceId(serviceId, `workload ${workload.metadata?.name}`);
|
||||
const expectedName = workload.kind === "Job" ? `${serviceId}-template` : serviceId;
|
||||
assert.equal(workload.metadata?.name, expectedName, `${serviceId} workload name`);
|
||||
assertDevNamespace(workload.metadata?.namespace, `${serviceId} workload namespace`);
|
||||
assert.equal(labelsFor(workload, serviceId)["app.kubernetes.io/name"], serviceId, `${serviceId} workload app label`);
|
||||
assertTemplateServiceId(workload, serviceId, `workload ${serviceId}`);
|
||||
|
||||
const containers = containerList(workload, `workload ${serviceId}`);
|
||||
assert.equal(containers.length, 1, `${serviceId} workload must have one container`);
|
||||
const container = containers[0];
|
||||
assert.equal(container.name, serviceId, `${serviceId} container name`);
|
||||
assertHwlabImage(container.image, serviceId, `${serviceId} container`);
|
||||
assertHealthProbe(container, serviceId, `${serviceId} container`);
|
||||
assertNoForbiddenSubstitutesDeep(container.env ?? [], `${serviceId} container env`);
|
||||
}
|
||||
}
|
||||
|
||||
function assertServices(services, guard) {
|
||||
assert.equal(services.kind, "List", "services kind");
|
||||
assertArray(services.items, "services items");
|
||||
|
||||
const serviceIds = services.items.map((item) => item.metadata?.labels?.[serviceIdLabel]);
|
||||
assertUnique(serviceIds, "k8s service ids");
|
||||
assertSameMembers(serviceIds, guard.requiredK3sSkeleton.requiredServiceServiceIds, "k8s service ids");
|
||||
|
||||
for (const service of services.items) {
|
||||
const serviceId = service.metadata?.labels?.[serviceIdLabel];
|
||||
assertServiceId(serviceId, `k8s service ${service.metadata?.name}`);
|
||||
assertMetadataServiceId(service, serviceId, `k8s service ${serviceId}`);
|
||||
assertNoExternalNameSubstitute(service, `k8s service ${serviceId}`);
|
||||
assert.equal(service.spec?.selector?.["app.kubernetes.io/name"], serviceId, `${serviceId} selector`);
|
||||
}
|
||||
}
|
||||
|
||||
function assertDevHealthConfig(configMap) {
|
||||
assert.equal(configMap.kind, "ConfigMap", "dev health contract kind");
|
||||
assertDevNamespace(configMap.metadata?.namespace, "dev health contract namespace");
|
||||
assert.equal(configMap.data?.endpoint, DEV_ENDPOINT, "dev health contract endpoint");
|
||||
assertRuntimePolicyText(configMap.data?.["runtime-substitute-policy"], "dev runtime substitute policy");
|
||||
}
|
||||
|
||||
function assertProdDisabled(prodKustomization, prodDisabled) {
|
||||
assert.equal(prodKustomization.kind, "Kustomization", "prod kustomization kind");
|
||||
assert.deepEqual(prodKustomization.resources, ["prod-disabled.yaml"], "prod kustomization resources");
|
||||
assert.equal(prodDisabled.kind, "ConfigMap", "prod disabled kind");
|
||||
assert.equal(prodDisabled.metadata?.labels?.["hwlab.pikastech.local/profile"], "prod", "prod disabled profile");
|
||||
assert.equal(
|
||||
prodDisabled.metadata?.labels?.["hwlab.pikastech.local/acceptance"],
|
||||
"disabled",
|
||||
"prod disabled acceptance"
|
||||
);
|
||||
assert.equal(prodDisabled.data?.status, "disabled", "prod disabled status");
|
||||
}
|
||||
|
||||
const guard = await readJSON("protocol/examples/runtime-boundary/guard.dev.json");
|
||||
assertGuardFixture(guard);
|
||||
|
||||
assertDeployManifest(await readJSON(guard.requiredManifest.path), guard);
|
||||
assertMasterHealthContract(await readJSON(guard.requiredHealthContract.path), guard);
|
||||
assertWorkloads(await readJSON(guard.requiredK3sSkeleton.workloadsPath), guard);
|
||||
assertServices(await readJSON(guard.requiredK3sSkeleton.servicesPath), guard);
|
||||
assertKustomizationDevOnly(await readJSON(guard.requiredK3sSkeleton.devKustomizationPath), "dev kustomization");
|
||||
assertDevHealthConfig(await readJSON(guard.requiredK3sSkeleton.devHealthContractPath));
|
||||
assertProdDisabled(
|
||||
await readJSON(guard.requiredK3sSkeleton.prodKustomizationPath),
|
||||
await readJSON(guard.requiredK3sSkeleton.prodDisabledPath)
|
||||
);
|
||||
|
||||
console.log(
|
||||
`validated HWLAB runtime boundary guard for ${SERVICE_IDS.length} services; forbidden substitutes: ${forbiddenRuntimeSubstitutes.join(", ")}`
|
||||
);
|
||||
Reference in New Issue
Block a user