Merge pull request #941 from pikasTech/fix/v02-agentrun-bundle-source-933
fix: require explicit AgentRun bundle source commit
This commit is contained in:
@@ -60,6 +60,7 @@ export function describeAgentRunAdapterAvailability(env = process.env, options =
|
|||||||
const blockers = [];
|
const blockers = [];
|
||||||
let managerUrl = null;
|
let managerUrl = null;
|
||||||
let repoUrl = null;
|
let repoUrl = null;
|
||||||
|
let resourceBundleSourceCommit = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
managerUrl = resolveAgentRunManagerUrl(env);
|
managerUrl = resolveAgentRunManagerUrl(env);
|
||||||
@@ -71,6 +72,11 @@ export function describeAgentRunAdapterAvailability(env = process.env, options =
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
blockers.push(agentRunAvailabilityBlocker(error, "repo-url"));
|
blockers.push(agentRunAvailabilityBlocker(error, "repo-url"));
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
resourceBundleSourceCommit = requireAgentRunSourceCommit(env);
|
||||||
|
} catch (error) {
|
||||||
|
blockers.push(agentRunAvailabilityBlocker(error, "resource-bundle-source-commit"));
|
||||||
|
}
|
||||||
|
|
||||||
const providerId = firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID, env.AGENTRUN_PROVIDER_ID, DEFAULT_PROVIDER_ID);
|
const providerId = firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID, env.AGENTRUN_PROVIDER_ID, DEFAULT_PROVIDER_ID);
|
||||||
const runnerNamespace = firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_RUNNER_NAMESPACE, env.AGENTRUN_RUNTIME_NAMESPACE, DEFAULT_RUNNER_NAMESPACE);
|
const runnerNamespace = firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_RUNNER_NAMESPACE, env.AGENTRUN_RUNTIME_NAMESPACE, DEFAULT_RUNNER_NAMESPACE);
|
||||||
@@ -145,6 +151,7 @@ export function describeAgentRunAdapterAvailability(env = process.env, options =
|
|||||||
managerHost,
|
managerHost,
|
||||||
repoUrl,
|
repoUrl,
|
||||||
repoHost,
|
repoHost,
|
||||||
|
resourceBundleSourceCommit,
|
||||||
managerConfigured: Boolean(managerUrl),
|
managerConfigured: Boolean(managerUrl),
|
||||||
repoConfigured: Boolean(repoUrl),
|
repoConfigured: Boolean(repoUrl),
|
||||||
internalServiceDns: managerHost === "agentrun-mgr.agentrun-v01.svc.cluster.local",
|
internalServiceDns: managerHost === "agentrun-mgr.agentrun-v01.svc.cluster.local",
|
||||||
@@ -235,6 +242,7 @@ export function initialAgentRunChatResult({ params = {}, options = {}, traceId }
|
|||||||
providerId: firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID, env.AGENTRUN_PROVIDER_ID, DEFAULT_PROVIDER_ID),
|
providerId: firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID, env.AGENTRUN_PROVIDER_ID, DEFAULT_PROVIDER_ID),
|
||||||
managerUrl: resolveAgentRunManagerUrl(env),
|
managerUrl: resolveAgentRunManagerUrl(env),
|
||||||
repoUrl: resolveAgentRunRepoUrl(env),
|
repoUrl: resolveAgentRunRepoUrl(env),
|
||||||
|
resourceBundleSourceCommit: requireAgentRunSourceCommit(env),
|
||||||
valuesPrinted: false
|
valuesPrinted: false
|
||||||
},
|
},
|
||||||
valuesPrinted: false
|
valuesPrinted: false
|
||||||
@@ -710,22 +718,20 @@ function newSessionIdAfterEviction(baseSessionId, traceId) {
|
|||||||
return baseSessionId + "-reset-" + profile;
|
return baseSessionId + "-reset-" + profile;
|
||||||
}
|
}
|
||||||
function buildAgentRunCreateRunInput({ params, env, traceId, backendProfile, sessionId, toolCapabilities = null }) {
|
function buildAgentRunCreateRunInput({ params, env, traceId, backendProfile, sessionId, toolCapabilities = null }) {
|
||||||
const commitId = fullSourceCommit(env);
|
const commitId = requireAgentRunSourceCommit(env);
|
||||||
const threadId = safeOpaqueId(params.threadId);
|
const threadId = safeOpaqueId(params.threadId);
|
||||||
const hwlabProjectId = firstNonEmpty(params.projectId);
|
const hwlabProjectId = firstNonEmpty(params.projectId);
|
||||||
const toolAliases = filteredResourceToolAliases(toolCapabilities);
|
const toolAliases = filteredResourceToolAliases(toolCapabilities);
|
||||||
const resourceBundleRef = commitId
|
const resourceBundleRef = {
|
||||||
? {
|
kind: "git",
|
||||||
kind: "git",
|
repoUrl: resolveAgentRunRepoUrl(env),
|
||||||
repoUrl: resolveAgentRunRepoUrl(env),
|
commitId,
|
||||||
commitId,
|
submodules: false,
|
||||||
submodules: false,
|
lfs: false,
|
||||||
lfs: false,
|
toolAliases,
|
||||||
toolAliases,
|
promptRefs: HWLAB_RESOURCE_PROMPT_REFS,
|
||||||
promptRefs: HWLAB_RESOURCE_PROMPT_REFS,
|
skillRefs: HWLAB_RESOURCE_SKILL_REFS
|
||||||
skillRefs: HWLAB_RESOURCE_SKILL_REFS
|
};
|
||||||
}
|
|
||||||
: null;
|
|
||||||
return {
|
return {
|
||||||
tenantId: firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_TENANT_ID, DEFAULT_TENANT_ID),
|
tenantId: firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_TENANT_ID, DEFAULT_TENANT_ID),
|
||||||
projectId: agentRunProjectIdForEnv(env),
|
projectId: agentRunProjectIdForEnv(env),
|
||||||
@@ -1705,20 +1711,13 @@ function resolveAgentRunRepoUrl(env = process.env) {
|
|||||||
return url.toString().replace(/\/+$/u, "");
|
return url.toString().replace(/\/+$/u, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
function fullSourceCommit(env) {
|
function requireAgentRunSourceCommit(env) {
|
||||||
for (const value of [
|
const text = String(env.HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT ?? "").trim().toLowerCase();
|
||||||
env.HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT,
|
if (/^[0-9a-f]{40}$/u.test(text)) return text;
|
||||||
env.HWLAB_BOOT_COMMIT,
|
throw Object.assign(new Error("HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT must be a full 40-character source commit before AgentRun dispatch"), {
|
||||||
env.HWLAB_GITOPS_SOURCE_COMMIT,
|
code: "agentrun_bundle_source_commit_invalid",
|
||||||
env.HWLAB_COMMIT_ID,
|
statusCode: 500
|
||||||
env.HWLAB_GIT_SHA,
|
});
|
||||||
env.GIT_COMMIT,
|
|
||||||
env.HWLAB_REVISION
|
|
||||||
]) {
|
|
||||||
const text = String(value ?? "").trim().toLowerCase();
|
|
||||||
if (/^[0-9a-f]{40}$/u.test(text)) return text;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function modelForBackendProfile(profile, env = process.env) {
|
function modelForBackendProfile(profile, env = process.env) {
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ function buildCodeAgentStructuredReadiness({ provider, dbDurable, sessionRunner,
|
|||||||
ready,
|
ready,
|
||||||
adapter: codeAgent?.adapter ?? codeAgent?.agentRun?.adapter ?? null,
|
adapter: codeAgent?.adapter ?? codeAgent?.agentRun?.adapter ?? null,
|
||||||
agentRunReady: agentRun ? codeAgent?.agentRun?.ready === true : null,
|
agentRunReady: agentRun ? codeAgent?.agentRun?.ready === true : null,
|
||||||
|
resourceBundleSourceCommit: agentRun ? codeAgent?.agentRun?.resourceBundleSourceCommit ?? null : null,
|
||||||
providerReady: provider?.ready === true,
|
providerReady: provider?.ready === true,
|
||||||
durableDbReady: dbDurable?.ready === true,
|
durableDbReady: dbDurable?.ready === true,
|
||||||
sessionRunnerReady: sessionRunner?.ready === true,
|
sessionRunnerReady: sessionRunner?.ready === true,
|
||||||
|
|||||||
@@ -725,6 +725,7 @@ test("cloud api health reports AgentRun adapter readiness without repo-owned cod
|
|||||||
AGENTRUN_MGR_URL: "http://agentrun-mgr.agentrun-v01.svc.cluster.local:8080",
|
AGENTRUN_MGR_URL: "http://agentrun-mgr.agentrun-v01.svc.cluster.local:8080",
|
||||||
HWLAB_CODE_AGENT_AGENTRUN_RUNNER_NAMESPACE: "agentrun-v01",
|
HWLAB_CODE_AGENT_AGENTRUN_RUNNER_NAMESPACE: "agentrun-v01",
|
||||||
HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: "G14",
|
HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: "G14",
|
||||||
|
HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT: "0123456789abcdef0123456789abcdef01234567",
|
||||||
HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE: "deepseek",
|
HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE: "deepseek",
|
||||||
HWLAB_CODE_AGENT_DEEPSEEK_MODEL: "deepseek-chat",
|
HWLAB_CODE_AGENT_DEEPSEEK_MODEL: "deepseek-chat",
|
||||||
HWLAB_BOOT_READ_URL: "http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/HWLAB.git",
|
HWLAB_BOOT_READ_URL: "http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/HWLAB.git",
|
||||||
@@ -779,6 +780,7 @@ test("cloud api health reports AgentRun adapter readiness without repo-owned cod
|
|||||||
assert.equal(payload.readiness.codeAgent.ready, true);
|
assert.equal(payload.readiness.codeAgent.ready, true);
|
||||||
assert.equal(payload.readiness.codeAgent.adapter, "agentrun-v01");
|
assert.equal(payload.readiness.codeAgent.adapter, "agentrun-v01");
|
||||||
assert.equal(payload.readiness.codeAgent.agentRunReady, true);
|
assert.equal(payload.readiness.codeAgent.agentRunReady, true);
|
||||||
|
assert.equal(payload.readiness.codeAgent.resourceBundleSourceCommit, "0123456789abcdef0123456789abcdef01234567");
|
||||||
assert.equal(payload.readiness.codeAgent.codexStdioFeasible, false);
|
assert.equal(payload.readiness.codeAgent.codexStdioFeasible, false);
|
||||||
assert.deepEqual(payload.readiness.codeAgent.currentBlockers, []);
|
assert.deepEqual(payload.readiness.codeAgent.currentBlockers, []);
|
||||||
const serialized = JSON.stringify(payload);
|
const serialized = JSON.stringify(payload);
|
||||||
@@ -795,6 +797,60 @@ test("cloud api health reports AgentRun adapter readiness without repo-owned cod
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("cloud api health blocks AgentRun adapter when explicit bundle source commit is missing", async () => {
|
||||||
|
const server = createCloudApiServer({
|
||||||
|
env: {
|
||||||
|
HWLAB_CODE_AGENT_ADAPTER: "agentrun-v01",
|
||||||
|
AGENTRUN_MGR_URL: "http://agentrun-mgr.agentrun-v01.svc.cluster.local:8080",
|
||||||
|
HWLAB_CODE_AGENT_AGENTRUN_RUNNER_NAMESPACE: "agentrun-v01",
|
||||||
|
HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: "G14",
|
||||||
|
HWLAB_COMMIT_ID: "0123456789abcdef0123456789abcdef01234567",
|
||||||
|
HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE: "deepseek",
|
||||||
|
HWLAB_BOOT_READ_URL: "http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/HWLAB.git",
|
||||||
|
HWLAB_CLOUD_DB_URL: "postgres://hwlab_test:password@db.internal.local:5432/hwlab",
|
||||||
|
HWLAB_CLOUD_DB_SSL_MODE: "disable"
|
||||||
|
},
|
||||||
|
dbProbe: {
|
||||||
|
probe: async ({ endpointSource, timeoutMs }) => ({
|
||||||
|
attempted: true,
|
||||||
|
networkAttempted: true,
|
||||||
|
endpointSource,
|
||||||
|
probeType: "tcp-connect",
|
||||||
|
endpointRedacted: true,
|
||||||
|
valueRedacted: true,
|
||||||
|
timeoutMs,
|
||||||
|
durationMs: 1,
|
||||||
|
result: "connected",
|
||||||
|
classification: "tcp_connected",
|
||||||
|
errorCode: null,
|
||||||
|
missingEnv: []
|
||||||
|
})
|
||||||
|
},
|
||||||
|
runtimeStore: {
|
||||||
|
async readiness() {
|
||||||
|
return durableReadyRuntime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { port } = server.address();
|
||||||
|
const response = await fetch(`http://127.0.0.1:${port}/health/live`);
|
||||||
|
assert.equal(response.status, 200);
|
||||||
|
const payload = await response.json();
|
||||||
|
assert.equal(payload.codeAgent.status, "blocked");
|
||||||
|
assert.equal(payload.codeAgent.ready, false);
|
||||||
|
assert.equal(payload.codeAgent.reason, "agentrun_bundle_source_commit_invalid");
|
||||||
|
assert.equal(payload.codeAgent.agentRun.ready, false);
|
||||||
|
assert.deepEqual(payload.codeAgent.blockerCodes, ["agentrun_bundle_source_commit_invalid"]);
|
||||||
|
} finally {
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
server.close((error) => (error ? reject(error) : resolve()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test("cloud api health blocks full Code Agent readiness when Codex stdio command probe fails", async () => {
|
test("cloud api health blocks full Code Agent readiness when Codex stdio command probe fails", async () => {
|
||||||
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-health-codex-stdio-probe-fail-"));
|
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-health-codex-stdio-probe-fail-"));
|
||||||
const codexHome = path.join(workspace, "codex-home");
|
const codexHome = path.join(workspace, "codex-home");
|
||||||
|
|||||||
Reference in New Issue
Block a user