@hasna/skills 0.10.50 → 0.10.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1909,7 +1909,7 @@ var {
1909
1909
  // src/server/maintenance-entry.ts
1910
1910
  import { closeSync, constants, fstatSync, lstatSync, openSync, readSync } from "fs";
1911
1911
  import { createHash as createHash3 } from "crypto";
1912
- var {SQL: SQL2 } = globalThis.Bun;
1912
+ var {SQL: SQL3 } = globalThis.Bun;
1913
1913
 
1914
1914
  // src/server/execution-grant-store.ts
1915
1915
  import { randomUUID } from "crypto";
@@ -3991,6 +3991,140 @@ async function inspectEnrollment(databaseUrl, input) {
3991
3991
  }
3992
3992
  }
3993
3993
 
3994
+ // src/server/schema-census.ts
3995
+ var {SQL: SQL2 } = globalThis.Bun;
3996
+
3997
+ class SchemaCensusError extends Error {
3998
+ code;
3999
+ constructor(code) {
4000
+ super(code);
4001
+ this.code = code;
4002
+ this.name = "SchemaCensusError";
4003
+ }
4004
+ }
4005
+ var refuse2 = (code) => {
4006
+ throw new SchemaCensusError(code);
4007
+ };
4008
+ var FIXED_SCHEMA = "public";
4009
+ var STATEMENT_TIMEOUT_MS = 5000;
4010
+ var LOCK_TIMEOUT_MS = 1000;
4011
+ var MAX_MIGRATION_VERSIONS = 128;
4012
+ var MAX_MIGRATION_VERSION_CHARS = 64;
4013
+ var MAX_IDENTIFIER_CHARS = 128;
4014
+ var MAX_SERVER_VERSION_CHARS = 256;
4015
+ var MAX_CENSUS_BYTES = 16 * 1024;
4016
+ var boundedText = (value, max) => {
4017
+ if (typeof value !== "string" || value.length === 0 || /[\u0000-\u001f\u007f]/.test(value))
4018
+ return refuse2("CENSUS_INVALID_RESULT");
4019
+ if (value.length > max)
4020
+ return refuse2("CENSUS_OUTPUT_UNBOUNDED");
4021
+ return value;
4022
+ };
4023
+ var boundedCount = (value) => {
4024
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
4025
+ return refuse2("CENSUS_INVALID_RESULT");
4026
+ return value;
4027
+ };
4028
+ async function inspectSchemaCensus(databaseUrl) {
4029
+ try {
4030
+ const url = new URL(databaseUrl);
4031
+ if (!["postgres:", "postgresql:"].includes(url.protocol) || !url.hostname)
4032
+ refuse2("CENSUS_POSTGRES_REQUIRED");
4033
+ } catch {
4034
+ refuse2("CENSUS_POSTGRES_REQUIRED");
4035
+ }
4036
+ let sql;
4037
+ try {
4038
+ sql = new SQL2(databaseUrl, { max: 1, connectionTimeout: 5, idleTimeout: 5 });
4039
+ return await sql.begin("ISOLATION LEVEL REPEATABLE READ READ ONLY", async (tx) => {
4040
+ await tx.unsafe("SET LOCAL statement_timeout = '5s'");
4041
+ await tx.unsafe("SET LOCAL lock_timeout = '1s'");
4042
+ const mode = await tx`SELECT current_setting('transaction_read_only') AS read_only,
4043
+ current_setting('transaction_isolation') AS isolation,
4044
+ current_setting('statement_timeout') AS statement_timeout,
4045
+ current_setting('lock_timeout') AS lock_timeout`;
4046
+ if (mode.length !== 1 || mode[0].read_only !== "on" || mode[0].isolation !== "repeatable read" || mode[0].statement_timeout !== "5s" || mode[0].lock_timeout !== "1s") {
4047
+ refuse2("CENSUS_FAILED");
4048
+ }
4049
+ const identity = await tx`SELECT current_database() AS database, current_user AS role,
4050
+ version() AS server_version, current_schema() AS schema`;
4051
+ if (identity.length !== 1)
4052
+ refuse2("CENSUS_INVALID_RESULT");
4053
+ const database = boundedText(identity[0].database, MAX_IDENTIFIER_CHARS);
4054
+ const role = boundedText(identity[0].role, MAX_IDENTIFIER_CHARS);
4055
+ const serverVersion = boundedText(identity[0].server_version, MAX_SERVER_VERSION_CHARS);
4056
+ if (identity[0].schema !== FIXED_SCHEMA)
4057
+ refuse2("CENSUS_TARGET_MISMATCH");
4058
+ const ledger = await tx`SELECT version FROM public.schema_migrations ORDER BY version LIMIT ${MAX_MIGRATION_VERSIONS + 1}`;
4059
+ if (ledger.length > MAX_MIGRATION_VERSIONS)
4060
+ refuse2("CENSUS_OUTPUT_UNBOUNDED");
4061
+ const versions = ledger.map((row) => boundedText(row.version, MAX_MIGRATION_VERSION_CHARS));
4062
+ const registryCount = await tx`SELECT count(*)::int AS rows FROM public.skills_registry`;
4063
+ const versionCount = await tx`SELECT count(*)::int AS rows FROM public.skills_versions`;
4064
+ if (registryCount.length !== 1 || versionCount.length !== 1)
4065
+ refuse2("CENSUS_INVALID_RESULT");
4066
+ const registryRows = boundedCount(registryCount[0].rows);
4067
+ const versionRows = boundedCount(versionCount[0].rows);
4068
+ const groups = await tx`SELECT lifecycle, (tombstoned_at IS NOT NULL) AS tombstoned, count(*)::int AS rows
4069
+ FROM public.skills_registry GROUP BY 1, 2 LIMIT 5`;
4070
+ if (groups.length > 4)
4071
+ refuse2("CENSUS_INVALID_RESULT");
4072
+ const lifecycle = { active: { live: 0, tombstoned: 0 }, archived: { live: 0, tombstoned: 0 } };
4073
+ for (const group of groups) {
4074
+ const name = group.lifecycle;
4075
+ const tombstoned = group.tombstoned;
4076
+ if (name !== "active" && name !== "archived" || typeof tombstoned !== "boolean")
4077
+ return refuse2("CENSUS_INVALID_RESULT");
4078
+ lifecycle[name][tombstoned ? "tombstoned" : "live"] = boundedCount(group.rows);
4079
+ }
4080
+ const epochColumn = await tx`SELECT count(*)::int AS rows FROM information_schema.columns
4081
+ WHERE table_schema = ${FIXED_SCHEMA} AND table_name = 'skills_registry' AND column_name = 'authorization_epoch'`;
4082
+ if (epochColumn.length !== 1)
4083
+ refuse2("CENSUS_INVALID_RESULT");
4084
+ const epochPresent = boundedCount(epochColumn[0].rows);
4085
+ if (epochPresent > 1)
4086
+ refuse2("CENSUS_INVALID_RESULT");
4087
+ let authorizationEpoch;
4088
+ if (epochPresent === 0)
4089
+ authorizationEpoch = { exists: false };
4090
+ else {
4091
+ const epochNulls = await tx`SELECT count(*)::int AS rows FROM public.skills_registry WHERE authorization_epoch IS NULL`;
4092
+ if (epochNulls.length !== 1)
4093
+ refuse2("CENSUS_INVALID_RESULT");
4094
+ authorizationEpoch = { exists: true, nullCount: boundedCount(epochNulls[0].rows) };
4095
+ }
4096
+ const result = {
4097
+ status: "inspected",
4098
+ database,
4099
+ role,
4100
+ serverVersion,
4101
+ schema: FIXED_SCHEMA,
4102
+ transaction: { readOnly: true, isolation: "repeatable read", statementTimeoutMs: STATEMENT_TIMEOUT_MS, lockTimeoutMs: LOCK_TIMEOUT_MS },
4103
+ migrations: { count: versions.length, versions },
4104
+ registry: { rows: registryRows },
4105
+ versions: { rows: versionRows },
4106
+ lifecycle,
4107
+ authorizationEpoch
4108
+ };
4109
+ if (Buffer.byteLength(JSON.stringify(result), "utf8") > MAX_CENSUS_BYTES)
4110
+ refuse2("CENSUS_OUTPUT_UNBOUNDED");
4111
+ return result;
4112
+ });
4113
+ } catch (error) {
4114
+ if (error instanceof SchemaCensusError)
4115
+ throw error;
4116
+ const state2 = error instanceof SQL2.PostgresError ? error.errno : undefined;
4117
+ const code = state2 === "42P01" || state2 === "42703" ? "CENSUS_SCHEMA_UNAVAILABLE" : state2 === "42501" ? "CENSUS_ACCESS_DENIED" : state2 === "25006" ? "CENSUS_WRITE_REFUSED" : state2 === "57014" || state2 === "55P03" ? "CENSUS_TIMEOUT" : ["08000", "08001", "08003", "08004", "08006", "08007", "08P01", "28000", "28P01", "57P03"].includes(state2 ?? "") ? "CENSUS_CONNECTION_FAILED" : "CENSUS_FAILED";
4118
+ throw new SchemaCensusError(code);
4119
+ } finally {
4120
+ try {
4121
+ await sql?.close({ timeout: 1 });
4122
+ } catch {
4123
+ throw new SchemaCensusError("CENSUS_FAILED");
4124
+ }
4125
+ }
4126
+ }
4127
+
3994
4128
  // src/server/maintenance-entry.ts
3995
4129
  class InspectionInputError extends Error {
3996
4130
  code;
@@ -3999,6 +4133,14 @@ class InspectionInputError extends Error {
3999
4133
  this.code = code;
4000
4134
  }
4001
4135
  }
4136
+
4137
+ class SchemaCensusInputError extends Error {
4138
+ code;
4139
+ constructor(code) {
4140
+ super(code);
4141
+ this.code = code;
4142
+ }
4143
+ }
4002
4144
  var MAX_MANIFEST_BYTES = 32 * 1024;
4003
4145
  function sha256(value) {
4004
4146
  return createHash3("sha256").update(value).digest("hex");
@@ -4109,6 +4251,41 @@ function readInspectionManifest(path, receiptPath) {
4109
4251
  }
4110
4252
  return parsed;
4111
4253
  }
4254
+ function readSchemaCensusManifest(path, receiptPath) {
4255
+ let input;
4256
+ let parsed;
4257
+ try {
4258
+ input = readBoundedJson(path);
4259
+ const value = input.value;
4260
+ if (!value || typeof value !== "object" || Array.isArray(value))
4261
+ throw new Error;
4262
+ const fields = ["app", "operation", "manifestVersion", "operationId", "stationId", "keyId", "orgId", "expiresAt", "manifestDigest"];
4263
+ if (Object.keys(value).length !== fields.length || fields.some((field) => !Object.hasOwn(value, field)))
4264
+ throw new Error;
4265
+ if (value.app !== "skills" || value.operation !== "inspect-schema" || value.manifestVersion !== 1)
4266
+ throw new Error;
4267
+ for (const field of ["operationId", "stationId", "keyId", "orgId"]) {
4268
+ const item = value[field];
4269
+ if (typeof item !== "string" || item.trim().length === 0 || item.length > 256 || /[\u0000-\u001f\u007f]/.test(item))
4270
+ throw new Error;
4271
+ }
4272
+ if (typeof value.expiresAt !== "string" || value.expiresAt.length > 64 || !Number.isFinite(Date.parse(value.expiresAt)) || Date.parse(value.expiresAt) <= Date.now())
4273
+ throw new Error;
4274
+ if (typeof value.manifestDigest !== "string" || !/^[a-f0-9]{64}$/.test(value.manifestDigest))
4275
+ throw new Error;
4276
+ if (sha256(canonical(value)) !== value.manifestDigest)
4277
+ throw new Error;
4278
+ parsed = value;
4279
+ } catch {
4280
+ throw new SchemaCensusInputError("INVALID_CENSUS_MANIFEST");
4281
+ }
4282
+ try {
4283
+ verifyOperatorReceipt(input, readBoundedJson(receiptPath).value);
4284
+ } catch {
4285
+ throw new SchemaCensusInputError("INVALID_OPERATOR_RECEIPT");
4286
+ }
4287
+ return parsed;
4288
+ }
4112
4289
  function registerMaintenance(parent) {
4113
4290
  const maintenance = parent.command("maintenance").description("Run protected, metadata-only Skills maintenance operations");
4114
4291
  maintenance.command("inspect-enrollment").description("Inspect one enrollment with a database-enforced read-only snapshot").requiredOption("--manifest <path>", "Fresh inspection authorization supplied by the protected task wrapper").requiredOption("--operator-receipt <path>", "Verified actor receipt written by the protected task wrapper").option("--json", "Output a safe JSON receipt", false).action(async (options) => {
@@ -4133,6 +4310,26 @@ function registerMaintenance(parent) {
4133
4310
  process.exitCode = 1;
4134
4311
  }
4135
4312
  });
4313
+ maintenance.command("inspect-schema").description("Census the fixed Skills schema and migration ledger with a database-enforced read-only snapshot").requiredOption("--manifest <path>", "Fresh census authorization supplied by the protected task wrapper").requiredOption("--operator-receipt <path>", "Verified actor receipt written by the protected task wrapper").option("--json", "Output a safe JSON receipt", false).action(async (options) => {
4314
+ try {
4315
+ const manifest = readSchemaCensusManifest(options.manifest, options.operatorReceipt);
4316
+ const census = await inspectSchemaCensus(process.env.HASNA_SKILLS_DATABASE_URL ?? "");
4317
+ console.log(JSON.stringify({
4318
+ ...census,
4319
+ operationId: manifest.operationId,
4320
+ keyId: manifest.keyId,
4321
+ orgId: manifest.orgId,
4322
+ stationId: manifest.stationId
4323
+ }));
4324
+ } catch (error) {
4325
+ const code = error instanceof SchemaCensusInputError || error instanceof SchemaCensusError ? error.code : "CENSUS_FAILED";
4326
+ if (options.json || !process.stdout.isTTY)
4327
+ console.log(JSON.stringify({ status: "failed", code }));
4328
+ else
4329
+ console.error(code);
4330
+ process.exitCode = 1;
4331
+ }
4332
+ });
4136
4333
  maintenance.command("enroll-publish").requiredOption("--manifest <path>", "Bounded target manifest supplied by the protected task wrapper").requiredOption("--operator-receipt <path>", "Verified actor receipt written by the protected task wrapper").option("--apply", "Commit the bounded scope update; defaults to dry-run", false).option("--json", "Output a safe JSON receipt", false).action(async (options) => {
4137
4334
  let manifest;
4138
4335
  let store;
@@ -4167,7 +4364,7 @@ function registerMaintenance(parent) {
4167
4364
  process.exitCode = 1;
4168
4365
  } catch (error) {
4169
4366
  const message = error instanceof Error ? error.message : "";
4170
- const state2 = error instanceof SQL2.PostgresError ? error.errno : undefined;
4367
+ const state2 = error instanceof SQL3.PostgresError ? error.errno : undefined;
4171
4368
  const code = state2 === "42P01" || state2 === "42703" ? "MAINTENANCE_SCHEMA_UNAVAILABLE" : state2 === "42501" ? "MAINTENANCE_ACCESS_DENIED" : state2 === "25006" ? "MAINTENANCE_WRITE_REFUSED" : state2 === "57014" || state2 === "55P03" ? "MAINTENANCE_TIMEOUT" : ["08000", "08001", "08003", "08004", "08006", "08007", "08P01", "28000", "28P01", "57P03"].includes(state2 ?? "") ? "MAINTENANCE_CONNECTION_FAILED" : message.includes("expired") || message.includes("expiry") ? "INVALID_EXPIRY" : message.includes("receipt") || message.includes("operator") ? "INVALID_OPERATOR_RECEIPT" : message.includes("manifest") || message.includes("input") ? "INVALID_MANIFEST" : message.includes("database") || message.includes("store") ? "STORE_UNAVAILABLE" : "MAINTENANCE_FAILED";
4172
4369
  if (options.json || !process.stdout.isTTY)
4173
4370
  console.log(JSON.stringify({ status: "failed", code }));