fix(ci): support current QuickStack app write contract
This commit is contained in:
@@ -23,7 +23,7 @@ const APP_FIELDS = [
|
|||||||
"securityContextRunAsGroup", "securityContextFsGroup", "securityContextPrivileged",
|
"securityContextRunAsGroup", "securityContextFsGroup", "securityContextPrivileged",
|
||||||
"gitUrl", "gitBranch", "gitUsername", "gitToken", "dockerfilePath", "replicas",
|
"gitUrl", "gitBranch", "gitUsername", "gitToken", "dockerfilePath", "replicas",
|
||||||
"envVars", "memoryReservation", "memoryLimit", "cpuReservation", "cpuLimit",
|
"envVars", "memoryReservation", "memoryLimit", "cpuReservation", "cpuLimit",
|
||||||
"webhookId", "ingressNetworkPolicy", "egressNetworkPolicy", "useNetworkPolicy",
|
"webhookId", "useNetworkPolicy",
|
||||||
"healthChechHttpGetPath", "healthCheckHttpScheme", "healthCheckHttpHeadersJson",
|
"healthChechHttpGetPath", "healthCheckHttpScheme", "healthCheckHttpHeadersJson",
|
||||||
"healthCheckHttpPort", "healthCheckPeriodSeconds", "healthCheckTimeoutSeconds",
|
"healthCheckHttpPort", "healthCheckPeriodSeconds", "healthCheckTimeoutSeconds",
|
||||||
"healthCheckFailureThreshold", "healthCheckTcpPort",
|
"healthCheckFailureThreshold", "healthCheckTcpPort",
|
||||||
@@ -31,7 +31,6 @@ const APP_FIELDS = [
|
|||||||
|
|
||||||
const COLLECTION_FIELDS = {
|
const COLLECTION_FIELDS = {
|
||||||
appDomains: ["id", "hostname", "port", "useSsl", "redirectHttps"],
|
appDomains: ["id", "hostname", "port", "useSsl", "redirectHttps"],
|
||||||
appPorts: ["id", "port"],
|
|
||||||
appNodePorts: ["id", "port", "nodePort", "protocol"],
|
appNodePorts: ["id", "port", "nodePort", "protocol"],
|
||||||
appFileMounts: ["id", "containerMountPath", "content"],
|
appFileMounts: ["id", "containerMountPath", "content"],
|
||||||
appVolumes: [
|
appVolumes: [
|
||||||
@@ -58,6 +57,11 @@ export function toSavePayload(app) {
|
|||||||
for (const [name, fields] of Object.entries(COLLECTION_FIELDS)) {
|
for (const [name, fields] of Object.entries(COLLECTION_FIELDS)) {
|
||||||
payload[name] = Array.isArray(app[name]) ? app[name].map((item) => pick(item, fields)) : [];
|
payload[name] = Array.isArray(app[name]) ? app[name].map((item) => pick(item, fields)) : [];
|
||||||
}
|
}
|
||||||
|
payload.appNetworkPolicy = app.appNetworkPolicy ? {
|
||||||
|
...pick(app.appNetworkPolicy, ["id", "allowInternetAccess"]),
|
||||||
|
rules: app.appNetworkPolicy.rules.map((rule) =>
|
||||||
|
pick(rule, ["id", "type", "targetAppId", "targetAgentId", "port", "protocol"])),
|
||||||
|
} : null;
|
||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -297,6 +297,32 @@ test("preserves response-only fields and existing environment secrets safely", (
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("uses the current QuickStack write contract and preserves network policy rules", () => {
|
||||||
|
const policy = {
|
||||||
|
id: "policy-one", appId: "app-one", allowInternetAccess: false,
|
||||||
|
rules: [
|
||||||
|
{ id: "rule-app", type: "APP", targetAppId: "database", targetAgentId: null, port: 5432, protocol: "TCP", targetApp: {} },
|
||||||
|
{ id: "rule-agent", type: "AGENT", targetAppId: null, targetAgentId: "agent-one", port: 9000, protocol: "TCP", policyId: "policy-one" },
|
||||||
|
{ type: "APP", targetAppId: "dns", port: 53, protocol: "UDP" },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const payload = toSavePayload(app({ appNetworkPolicy: policy, networkPolicyMode: "legacy" }));
|
||||||
|
assert.deepEqual(payload.appNetworkPolicy, {
|
||||||
|
id: "policy-one", allowInternetAccess: false,
|
||||||
|
rules: [
|
||||||
|
{ id: "rule-app", type: "APP", targetAppId: "database", targetAgentId: null, port: 5432, protocol: "TCP" },
|
||||||
|
{ id: "rule-agent", type: "AGENT", targetAppId: null, targetAgentId: "agent-one", port: 9000, protocol: "TCP" },
|
||||||
|
{ type: "APP", targetAppId: "dns", port: 53, protocol: "UDP" },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
for (const field of ["appPorts", "ingressNetworkPolicy", "egressNetworkPolicy", "networkPolicyMode"]) {
|
||||||
|
assert.equal(Object.hasOwn(payload, field), false);
|
||||||
|
}
|
||||||
|
assert.equal(toSavePayload(app()).appNetworkPolicy, null);
|
||||||
|
assert.deepEqual(toSavePayload(app({ appNetworkPolicy: { allowInternetAccess: true, rules: [] } })).appNetworkPolicy,
|
||||||
|
{ allowInternetAccess: true, rules: [] });
|
||||||
|
});
|
||||||
|
|
||||||
test("overrides only declared existing QuickStack volume mount paths", () => {
|
test("overrides only declared existing QuickStack volume mount paths", () => {
|
||||||
const volumes = [
|
const volumes = [
|
||||||
{ id: "volume-local", sharedVolumeId: "shared-volume", containerMountPath: "/old" },
|
{ id: "volume-local", sharedVolumeId: "shared-volume", containerMountPath: "/old" },
|
||||||
@@ -348,12 +374,19 @@ test("postflight waits for the exact expected identity", async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("failed public verification restores and redeploys the previous source", async () => {
|
test("failed public verification restores and redeploys the previous source", async () => {
|
||||||
const original = app();
|
const original = app({ appNetworkPolicy: {
|
||||||
|
id: "policy-one", allowInternetAccess: false,
|
||||||
|
rules: [{ id: "rule-one", type: "APP", targetAppId: "database", port: 5432, protocol: "TCP" }],
|
||||||
|
} });
|
||||||
let current = original;
|
let current = original;
|
||||||
let deployments = 0;
|
let deployments = 0;
|
||||||
const client = {
|
const client = {
|
||||||
getApp: async () => current,
|
getApp: async () => current,
|
||||||
saveApp: async (payload) => { current = { ...current, ...payload }; },
|
saveApp: async (payload) => {
|
||||||
|
assert.deepEqual(payload.appNetworkPolicy, original.appNetworkPolicy);
|
||||||
|
assert.equal(Object.hasOwn(payload, "appPorts"), false);
|
||||||
|
current = { ...current, ...payload };
|
||||||
|
},
|
||||||
deployApp: async () => ({ deploymentId: `deployment-${++deployments}` }),
|
deployApp: async () => ({ deploymentId: `deployment-${++deployments}` }),
|
||||||
getDeployment: async (_appId, deploymentId) => ({ deploymentId, status: "DEPLOYED" }),
|
getDeployment: async (_appId, deploymentId) => ({ deploymentId, status: "DEPLOYED" }),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user