Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions actions/setup/js/error_codes.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ const ERR_SYSTEM = "ERR_SYSTEM";
/** @type {string} Safe output validation/input errors (legacy numeric taxonomy) */
const SAFE_OUTPUT_E001 = "E001";

/** @type {string} Safe output limit violations (legacy numeric taxonomy) */
const SAFE_OUTPUT_E002 = "E002";

/** @type {string} Safe output API/operation guard failures (legacy numeric taxonomy) */
const SAFE_OUTPUT_E007 = "E007";

Expand Down Expand Up @@ -80,6 +83,7 @@ module.exports = {
ERR_PARSE,
ERR_SYSTEM,
SAFE_OUTPUT_E001,
SAFE_OUTPUT_E002,
SAFE_OUTPUT_E007,
SAFE_OUTPUT_E009,
SAFE_OUTPUT_E010,
Expand Down
8 changes: 8 additions & 0 deletions actions/setup/js/error_codes.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const {
ERR_PARSE,
ERR_SYSTEM,
SAFE_OUTPUT_E001,
SAFE_OUTPUT_E002,
SAFE_OUTPUT_E007,
SAFE_OUTPUT_E009,
SAFE_OUTPUT_E010,
Expand All @@ -28,6 +29,7 @@ describe("error_codes", () => {
expect(ERR_PARSE).toBeDefined();
expect(ERR_SYSTEM).toBeDefined();
expect(SAFE_OUTPUT_E001).toBeDefined();
expect(SAFE_OUTPUT_E002).toBeDefined();
expect(SAFE_OUTPUT_E007).toBeDefined();
expect(SAFE_OUTPUT_E009).toBeDefined();
expect(SAFE_OUTPUT_E010).toBeDefined();
Expand All @@ -46,6 +48,7 @@ describe("error_codes", () => {
ERR_PARSE,
ERR_SYSTEM,
SAFE_OUTPUT_E001,
SAFE_OUTPUT_E002,
SAFE_OUTPUT_E007,
SAFE_OUTPUT_E009,
SAFE_OUTPUT_E010,
Expand Down Expand Up @@ -94,6 +97,10 @@ describe("error_codes", () => {
expect(SAFE_OUTPUT_E001).toBe("E001");
});

it("SAFE_OUTPUT_E002 is 'E002'", () => {
expect(SAFE_OUTPUT_E002).toBe("E002");
});

it("SAFE_OUTPUT_E007 is 'E007'", () => {
expect(SAFE_OUTPUT_E007).toBe("E007");
});
Expand Down Expand Up @@ -146,6 +153,7 @@ describe("error_codes", () => {
ERR_PARSE,
ERR_SYSTEM,
SAFE_OUTPUT_E001,
SAFE_OUTPUT_E002,
SAFE_OUTPUT_E007,
SAFE_OUTPUT_E009,
SAFE_OUTPUT_E010,
Expand Down
3 changes: 2 additions & 1 deletion actions/setup/js/finish_work_queue_claim.cjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ts-check
"use strict";
const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const log = require("./work_queue_logging.cjs").createWorkQueueLogger("claims");

const { isProxy } = require("node:util").types;
Expand Down Expand Up @@ -49,7 +50,7 @@ function snapshotClaimDelivery(proof) {
*/
function inspect(value, depth) {
if (value === null || typeof value !== "object") return;
if (depth > 64 || ancestors.has(value) || isProxy(value)) throw new Error("work_queue_delivery_proof_invalid");
if (depth > 64 || ancestors.has(value) || isProxy(value)) throw new Error(`${SAFE_OUTPUT_E001}: work_queue_delivery_proof_invalid`);
ancestors.add(value);
for (const descriptor of Object.values(Object.getOwnPropertyDescriptors(value))) {
if (descriptor.get || descriptor.set) throw new Error("work_queue_delivery_proof_invalid");
Expand Down
3 changes: 2 additions & 1 deletion actions/setup/js/report_failed_jobs.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @ts-check
/// <reference types="@actions/github-script" />

const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const { getErrorMessage } = require("./error_helpers.cjs");
const { fetchAndLogRateLimit } = require("./github_rate_limit_logger.cjs");
const { renderTemplateFromFile, getPromptPath } = require("./messages_core.cjs");
Expand Down Expand Up @@ -71,7 +72,7 @@ async function getFailedNonBuiltinJobs() {
jobResults = JSON.parse(process.env.GH_AW_JOB_RESULTS || "");
jobDisplayNames = JSON.parse(process.env.GH_AW_JOB_DISPLAY_NAMES || "");
} catch (error) {
throw new Error(`Failed to parse failed-job reporting metadata: ${getErrorMessage(error)}`, { cause: error });
throw new Error(`${SAFE_OUTPUT_E001}: Failed to parse failed-job reporting metadata: ${getErrorMessage(error)}`, { cause: error });
}
if (!jobResults || typeof jobResults !== "object" || Array.isArray(jobResults) || !jobDisplayNames || typeof jobDisplayNames !== "object" || Array.isArray(jobDisplayNames)) {
throw new Error("GH_AW_JOB_RESULTS and GH_AW_JOB_DISPLAY_NAMES must be JSON objects");
Expand Down
3 changes: 2 additions & 1 deletion actions/setup/js/safe_output_action_handler.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* @typedef {import('./types/handler-factory').HandlerFactoryFunction} HandlerFactoryFunction
*/

const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const { replaceTemporaryIdReferences } = require("./temporary_id.cjs");
const { getErrorMessage } = require("./error_helpers.cjs");
const { sanitizeContent } = require("./sanitize_content.cjs");
Expand Down Expand Up @@ -60,7 +61,7 @@ async function main(config = {}) {
* @returns {Promise<Object>} Result with success/error status
*/
return async function handleCustomAction(message, resolvedTemporaryIds, temporaryIdMap = new Map()) {
if (currentClaimHandle() !== factoryClaim) throw new Error("Custom action handler cannot escape its original Claim factory");
if (currentClaimHandle() !== factoryClaim) throw new Error(`${SAFE_OUTPUT_E001}: Custom action handler cannot escape its original Claim factory`);
if (factoryIdentity) assertClaimIdentity(factoryIdentity);
// Enforce once-only constraint
if (called) {
Expand Down
4 changes: 2 additions & 2 deletions actions/setup/js/work_queue_binding.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check
"use strict";

const { SAFE_OUTPUT_E002 } = require("./error_codes.cjs");
const queue = require("./work_queue_replay.cjs");
const store = require("./work_queue_store.cjs");
const { canonical, digest, parseStrictJSON } = require("./work_queue_codec.cjs");
Expand All @@ -13,7 +13,7 @@ const { isStagedMode } = require("./safe_output_helpers.cjs");
function policyProposalFor(options) {
const raw = Object.hasOwn(options, "policyProposal") ? options.policyProposal : process.env.GH_AW_WORK_QUEUE_POLICY;
if (raw === undefined) return;
if (typeof raw === "string" && Buffer.byteLength(raw, "utf8") > 4 * 1024 * 1024) throw new Error("work_queue_policy_proposal_limit");
if (typeof raw === "string" && Buffer.byteLength(raw, "utf8") > 4 * 1024 * 1024) throw new Error(`${SAFE_OUTPUT_E002}: work_queue_policy_proposal_limit`);
const proposal = typeof raw === "string" ? parseStrictJSON(raw) : raw;
validatePolicy(proposal);
return proposal;
Expand Down
4 changes: 2 additions & 2 deletions actions/setup/js/work_queue_claim_adapters.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check
"use strict";

const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
Expand Down Expand Up @@ -33,7 +33,7 @@ const DECLARED_EFFECT_TYPES = new Set(ADAPTER_EFFECT_TYPES);

function builtinMessageFields(message) {
const fields = builtinAdapterFields(message.type);
if (!fields) throw new Error("Unsupported native builtin Claim verifier");
if (!fields) throw new Error(`${SAFE_OUTPUT_E001}: Unsupported native builtin Claim verifier`);
const metadata = new Set(["type", "claim_handle", "claim_id", "work_id", "repo", "temporary_id"]);
if (Object.keys(message).some(field => !metadata.has(field) && !fields.includes(field))) throw new Error("Native builtin Claim verifier cannot ignore undeclared message fields");
builtinTargetNumber(message);
Expand Down
4 changes: 2 additions & 2 deletions actions/setup/js/work_queue_code_coverage.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check
"use strict";

const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
Expand All @@ -25,7 +25,7 @@ const privateReceipts = new WeakMap();
/** @param {{ "target-ref"?: string, "coverage-dir"?: string, max?: number, "wait-for-processing-timeout"?: number, staged?: boolean }} [config] @param {import("./types/work-queue-native-client").ClaimNativeClient} [suppliedClient] */
async function main(config = {}, suppliedClient) {
const handle = currentClaimHandle();
if (!handle) throw new Error("Queue coverage requires a Claim factory");
if (!handle) throw new Error(`${SAFE_OUTPUT_E001}: Queue coverage requires a Claim factory`);
const factoryIdentity = claimIdentity(handle);
/** @type {import("./types/work-queue-native-client").ClaimNativeClient} */
const selectedClient = suppliedClient || global.github;
Expand Down
4 changes: 2 additions & 2 deletions actions/setup/js/work_queue_code_scanning.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check
"use strict";

const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const crypto = require("crypto");
const path = require("path");
const zlib = require("zlib");
Expand All @@ -24,7 +24,7 @@ const privateReceipts = new WeakMap();
/** @param {{ "target-repo"?: string, "target-ref"?: string, driver?: string, max?: number, workflow_filename?: string, staged?: boolean }} [config] @param {import("./types/work-queue-native-client").ClaimNativeClient} [suppliedClient] */
async function main(config = {}, suppliedClient) {
const handle = currentClaimHandle();
if (!handle) throw new Error("Queue code scanning requires a Claim factory");
if (!handle) throw new Error(`${SAFE_OUTPUT_E001}: Queue code scanning requires a Claim factory`);
const factoryIdentity = claimIdentity(handle);
/** @type {import("./types/work-queue-native-client").ClaimNativeClient} */
const selectedClient = suppliedClient || global.github;
Expand Down
4 changes: 2 additions & 2 deletions actions/setup/js/work_queue_control_adapter.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check
"use strict";

const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const { parseStrictJSON, utf8Compare } = require("./work_queue_codec.cjs");
const { loadQueue } = require("./work_queue_binding.cjs");
const { readStagedIntentBatch } = require("./work_queue_intents.cjs");
Expand All @@ -27,7 +27,7 @@ const { normalizeDispatchCredential, createDispatchCredentialValidator } = requi

function credentialBindings(raw) {
const value = raw === undefined ? {} : parseStrictJSON(raw);
if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).length > 64) throw new Error("work_queue_dependency_credentials_invalid");
if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).length > 64) throw new Error(`${SAFE_OUTPUT_E001}: work_queue_dependency_credentials_invalid`);
const normalized = new Map();
for (const [repository, variable] of Object.entries(value)) {
if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9._-]+$/.test(repository) || typeof variable !== "string" || !/^GH_AW_WORK_QUEUE_DEPENDENCY_READ_TOKEN_(?:0|[1-9][0-9]*)$/.test(variable)) throw new Error("work_queue_dependency_credentials_invalid");
Expand Down
3 changes: 2 additions & 1 deletion actions/setup/js/work_queue_dispatch.cjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ts-check
"use strict";
const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const log = require("./work_queue_logging.cjs").createWorkQueueLogger("dispatch");

const { canonical, closed, digest, integer } = require("./work_queue_codec.cjs");
Expand All @@ -22,7 +23,7 @@ const { normalizeDispatchCredential, createDispatchCredentialValidator, isDispat

function assertQueueControlRole(options) {
const runtime = resolveWorkQueueRuntime(options.context?.payload, { role: options.role, requireAssignment: options.requireAssignment });
if (runtime.role === "observer") throw new Error("work_queue_observer_read_only");
if (runtime.role === "observer") throw new Error(`${SAFE_OUTPUT_E001}: work_queue_observer_read_only`);
return runtime;
}

Expand Down
4 changes: 2 additions & 2 deletions actions/setup/js/work_queue_git_tree_adapter.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check
"use strict";

const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const crypto = require("crypto");
const path = require("path");
const { canonical, closed, digest, utf8Compare } = require("./work_queue_codec.cjs");
Expand All @@ -26,7 +26,7 @@ function validateGitTreeAdapter(adapter) {
closed(adapter["git-tree"], ["base-revision", "branch-prefix"], ["pull-request", "base-branch"], "trusted code adapter");
const config = adapter["git-tree"];
if (!REVISION.test(config["base-revision"]) || typeof config["branch-prefix"] !== "string" || !/^[A-Za-z0-9_-]+(?:\/[A-Za-z0-9_-]+)*$/.test(config["branch-prefix"]) || config["branch-prefix"].length > 128)
throw new Error("Trusted code adapter requires an immutable base revision and fixed branch namespace");
throw new Error(`${SAFE_OUTPUT_E001}: Trusted code adapter requires an immutable base revision and fixed branch namespace`);
if (config["pull-request"] !== undefined && typeof config["pull-request"] !== "boolean") throw new Error("Trusted code adapter pull-request must be boolean");
if (config["pull-request"] === true && (typeof config["base-branch"] !== "string" || !/^[A-Za-z0-9_-]+(?:\/[A-Za-z0-9_-]+)*$/.test(config["base-branch"]) || config["base-branch"].length > 128))
throw new Error("Trusted code adapter pull request requires a fixed base branch");
Expand Down
4 changes: 2 additions & 2 deletions actions/setup/js/work_queue_graphql_adapter.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check
"use strict";

const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const { canonical, canonicalBytes, closed, digest, utf8Compare } = require("./work_queue_codec.cjs");
const { assertClaimAuthorized, currentClaimHandle, claimIdentity, assertClaimIdentity, receiptMatchesClaim, createClaimResourceVerification, withClaimResourceVerification } = require("./work_queue_claim_scope.cjs");
const { resolveRepositoryTarget } = require("./work_queue_effect_resource.cjs");
Expand Down Expand Up @@ -39,7 +39,7 @@ function validateGraphqlAdapter(adapter) {
const config = adapter.graphql;
closed(config, ["mutation", "input-type", "response-field", "resource-type", "resource-kind", "repository-field", "repository-input", "permission", "fields"], ["number-field"], "trusted GraphQL adapter");
for (const field of ["mutation", "input-type", "response-field", "resource-type"]) {
if (typeof config[field] !== "string" || config[field].length > 128 || !NAME.test(config[field]) || RESERVED.has(config[field])) throw new Error("Trusted GraphQL adapter requires fixed native operation names");
if (typeof config[field] !== "string" || config[field].length > 128 || !NAME.test(config[field]) || RESERVED.has(config[field])) throw new Error(`${SAFE_OUTPUT_E001}: Trusted GraphQL adapter requires fixed native operation names`);
}
if (!["none", "repositoryId", "repositoryNameWithOwner"].includes(config["repository-input"])) throw new Error("Trusted GraphQL adapter requires explicit repository input binding");
if (!["checks", "contents", "issues", "pull-requests", "deployments", "discussions"].includes(config.permission)) throw new Error("Trusted GraphQL adapter requires an explicit native write permission");
Expand Down
5 changes: 3 additions & 2 deletions actions/setup/js/work_queue_issues.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check
"use strict";

const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const { canonical, closed, digest, parseStrictJSON, queueError } = require("./work_queue_codec.cjs");
const { actorFromContext } = require("./work_queue_policy.cjs");
const { authenticatePublisher } = require("./work_queue_native.cjs");
Expand All @@ -22,7 +22,8 @@ function issuesConfiguration(value) {
if (value === true) return { label: "work" };
closed(value, [], ["label", "status-field"], "work-queue issues");
for (const [key, field] of Object.entries(value)) {
if (typeof field !== "string" || !field.trim() || field.includes("${{") || Buffer.byteLength(field) > 256 || /[\x00-\x1f\x7f]/.test(field)) throw queueError("projection_invalid", `${key} must be a nonblank bounded literal`);
if (typeof field !== "string" || !field.trim() || field.includes("${{") || Buffer.byteLength(field) > 256 || /[\x00-\x1f\x7f]/.test(field))
throw queueError("projection_invalid", `${SAFE_OUTPUT_E001}: ${key} must be a nonblank bounded literal`);
}
return { label: "work", ...value };
}
Expand Down
4 changes: 2 additions & 2 deletions actions/setup/js/work_queue_prepare_claim_script.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check
"use strict";

const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const fs = require("fs");
const path = require("path");
const { closed, parseStrictJSON, identity } = require("./work_queue_codec.cjs");
Expand All @@ -11,7 +11,7 @@ async function main() {
const inputFile = process.env.GH_AW_CLAIM_INPUT;
const outputFile = process.env.GH_AW_CLAIM_OUTPUT;
const runtimeRoot = process.env.RUNNER_TEMP;
if (!inputFile || !outputFile || !runtimeRoot) throw new Error("Claim script requires the compiler-produced isolated paths");
if (!inputFile || !outputFile || !runtimeRoot) throw new Error(`${SAFE_OUTPUT_E001}: Claim script requires the compiler-produced isolated paths`);
const input = parseStrictJSON(fs.readFileSync(inputFile, "utf8"));
closed(input, ["version", "claim_handle", "type", "messages"], [], "Claim script input");
identity(input.claim_handle, "prepared Claim handle");
Expand Down
3 changes: 2 additions & 1 deletion actions/setup/js/work_queue_reconciler.cjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ts-check
"use strict";
const { SAFE_OUTPUT_E007 } = require("./error_codes.cjs");
const log = require("./work_queue_logging.cjs").createWorkQueueLogger("reconciler");

const { canonical, digest, integer } = require("./work_queue_codec.cjs");
Expand Down Expand Up @@ -66,7 +67,7 @@ async function discoverRuns(options, expected) {
headers: { "X-GitHub-Api-Version": API_VERSION },
request: { retries: 0, timeout: 15000 },
});
if (response.status !== undefined && response.status !== 200) throw new Error("native_discovery_unavailable");
if (response.status !== undefined && response.status !== 200) throw new Error(`${SAFE_OUTPUT_E007}: native_discovery_unavailable`);
const runs = response.data?.workflow_runs;
if (!Array.isArray(runs)) throw new Error("native_discovery_invalid");
log.debug("discovery.page", { page, runs: runs.length });
Expand Down
5 changes: 3 additions & 2 deletions actions/setup/js/work_queue_rest_adapter.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check
"use strict";

const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const { resolveRepositoryTarget, resolveParentResourceTarget } = require("./work_queue_effect_resource.cjs");

const { canonical, canonicalBytes, closed } = require("./work_queue_codec.cjs");
Expand Down Expand Up @@ -33,7 +33,8 @@ const RESERVED = new Set([
const privateReceipts = new WeakMap();

function routeFields(route) {
if (typeof route !== "string" || !/^\/repos\/\{owner\}\/\{repo\}\/[A-Za-z0-9_{}./-]+$/.test(route) || route.includes("..") || route.includes("//")) throw new Error("Trusted REST adapter requires a fixed repository-relative route");
if (typeof route !== "string" || !/^\/repos\/\{owner\}\/\{repo\}\/[A-Za-z0-9_{}./-]+$/.test(route) || route.includes("..") || route.includes("//"))
throw new Error(`${SAFE_OUTPUT_E001}: Trusted REST adapter requires a fixed repository-relative route`);
const fields = [...route.matchAll(/\{([A-Za-z_][A-Za-z_0-9]*)\}/g)].map(match => match[1]);
if (route.replace(/\{[A-Za-z_][A-Za-z_0-9]*\}/g, "").match(/[{}]/)) throw new Error("Malformed trusted REST adapter route");
return fields;
Expand Down
4 changes: 2 additions & 2 deletions actions/setup/js/work_queue_upload_assets.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check
"use strict";

const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
Expand All @@ -26,7 +26,7 @@ const receipts = new WeakMap();
/** @param {{ "target-repo"?: string, "assets-dir"?: string, "allowed-exts"?: string[], "max-size"?: number, max?: number, branch?: string, staged?: boolean }} [config] @param {import("./types/work-queue-native-client").ClaimNativeClient} [suppliedClient] */
async function main(config = {}, suppliedClient) {
const factoryClaim = currentClaimHandle();
if (!factoryClaim) throw new Error("Queue asset adapter requires an immutable Claim factory");
if (!factoryClaim) throw new Error(`${SAFE_OUTPUT_E001}: Queue asset adapter requires an immutable Claim factory`);
const factoryIdentity = claimIdentity(factoryClaim);
/** @type {import("./types/work-queue-native-client").ClaimNativeClient} */
const selectedClient = suppliedClient || global.github;
Expand Down
4 changes: 2 additions & 2 deletions actions/setup/js/write_work_queue_snapshot.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check
"use strict";

const { SAFE_OUTPUT_E001 } = require("./error_codes.cjs");
const fs = require("fs");
const path = require("path");
const { serializeTransactionLog, replayTransactions } = require("./work_queue_replay.cjs");
Expand Down Expand Up @@ -28,7 +28,7 @@ async function main(options = {}) {
};
const outputPath = options.snapshotPath || process.env.GH_AW_WORK_QUEUE_SNAPSHOT || SNAPSHOT_PATH;
const runtime = resolveWorkQueueRuntime(configuration.context.payload, { role: options.role, requireAssignment: options.requireAssignment });
if (runtime.role === "observer" && options.initializationContext !== undefined) throw new Error("work_queue_observer_read_only");
if (runtime.role === "observer" && options.initializationContext !== undefined) throw new Error(`${SAFE_OUTPUT_E001}: work_queue_observer_read_only`);
const readConfiguration = runtime.role === "observer" ? { ...configuration, policyProposal: undefined } : configuration;
let latest = await loadQueue(readConfiguration);
if (!latest.projection.policy && !(runtime.role !== "worker" && latest.sha === null && latest.transactions.length === 0)) throw new Error("work_queue_policy_missing");
Expand Down
Loading