@chain305/x-security 0.2.1 → 0.2.3

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.
package/README.md CHANGED
@@ -1,6 +1,24 @@
1
- # Writ CLI
1
+ # x-security CLI
2
2
 
3
- Compile, validate, test, and report on `x-security` policies in OpenAPI specs deterministic, no LLM calls, no API keys.
3
+ Your API gateway and WAF already ship most of the security you need auth, rate
4
+ limits, request validation, ownership/BOLA rules. Most teams run them on
5
+ defaults. `x-security` lets you write that policy **once**, as an extension of
6
+ the OpenAPI spec you already have, and compile it to whichever gateway you run.
7
+
8
+ - **No new DSL** — policy lives in your OpenAPI file, next to the route it protects.
9
+ - **No vendor lock-in** — one spec compiles to Kong, Coraza, BunkerWeb, OpenAppSec, Envoy, or a firewall bundle. Switch gateways without rewriting a line of policy.
10
+ - **No config drift** — the spec is the source of truth; it versions and diffs like code, and `validate` catches drift against a running gateway.
11
+
12
+ Deterministic. No LLM calls, no API keys.
13
+
14
+ ## Install
15
+
16
+ ```
17
+ npm i -g @chain305/x-security # installs the `xsecurity` command
18
+ xsecurity --help
19
+ ```
20
+
21
+ Or run it without installing:
4
22
 
5
23
  ```
6
24
  npx @chain305/x-security --help
package/bin/xsecurity.mjs CHANGED
@@ -25252,7 +25252,7 @@ var init_x_security_schema = __esm({
25252
25252
  $schema: "https://json-schema.org/draft/2020-12/schema",
25253
25253
  $id: "https://usewaf.com/schemas/x-security/v0.8.json",
25254
25254
  title: "x-security",
25255
- description: "Vendor-neutral OpenAPI extension declaring per-endpoint API security policy. Writ compiles this into Kong, Coraza, BunkerWeb, OpenAppSec, Cloudflare, AWS API Gateway, and host-firewall configurations. v0.8 (deferred-residuals) adds: graphql.operations[] per-operation authz + cost (capKey graphql.operations.authz, API1/API5, OVERRIDE-ONLY everywhere \u2014 requires an operator-supplied GraphQL-aware processor; the coarse block limits get the distinct capKey graphql.staticLimits, API4); request.serializeBy + request.concurrencyLimit live-concurrency serialization (API6, PARTIAL at best \u2014 edge serialization only, NOT in-handler transaction atomicity); and request.dataAtRest ADVISORY-ONLY at-rest posture declaration (Writ-native SSEC-STORAGE, NOT gateway-enforced \u2014 compiles to nothing, drives an out-of-band scan finding). The unreachable residuals token-entropy and session-rotation get ZERO new fields (detect-and-flag / documented gateway non-goal). v0.7 (edge-enforceable-residuals) adds: injectionGuard sinks 'deserialization' (SSEC-INJECTION) and 'ai-prompt' (Writ-native SSEC-PROMPT); top-level audit logging policy (logging, Writ-native SSEC-AUDIT); response.forbidArrayRoot JSON-hijacking defense (API3); request.idempotencyKey replay/double-submit defense (API6); and capability wiring for the already-declared authentication.passwordPolicy / authentication.accountLockout enforcement (API2). v0.6 added: per-arg injection hardening (W19 request.schema.<f>.injectionGuard, attributed to the Writ-native SSEC-INJECTION category). v0.5 added: identity-flexibility (S-10 RuleRef namespaces: principal/session/header), outbound trust (S-11 outboundCalls), auth depth (S-12 mfa/lockout/passwordPolicy/tokenSources), error scrubbing (S-13), composite-ID semantics (S-14 identifier combinator), open-redirect (S-15 redirectAllowedDomains), session fixation (S-16 sessionRotateOnAuth), nonce replay (S-17 nonceCacheTtl), TLS floor (S-18 tls).",
25255
+ description: "Vendor-neutral OpenAPI extension declaring per-endpoint API security policy. x-security compiles this into Kong, Coraza, BunkerWeb, OpenAppSec, Cloudflare, AWS API Gateway, and host-firewall configurations. v0.8 (deferred-residuals) adds: graphql.operations[] per-operation authz + cost (capKey graphql.operations.authz, API1/API5, OVERRIDE-ONLY everywhere \u2014 requires an operator-supplied GraphQL-aware processor; the coarse block limits get the distinct capKey graphql.staticLimits, API4); request.serializeBy + request.concurrencyLimit live-concurrency serialization (API6, PARTIAL at best \u2014 edge serialization only, NOT in-handler transaction atomicity); and request.dataAtRest ADVISORY-ONLY at-rest posture declaration (x-security-native SSEC-STORAGE, NOT gateway-enforced \u2014 compiles to nothing, drives an out-of-band scan finding). The unreachable residuals token-entropy and session-rotation get ZERO new fields (detect-and-flag / documented gateway non-goal). v0.7 (edge-enforceable-residuals) adds: injectionGuard sinks 'deserialization' (SSEC-INJECTION) and 'ai-prompt' (x-security-native SSEC-PROMPT); top-level audit logging policy (logging, x-security-native SSEC-AUDIT); response.forbidArrayRoot JSON-hijacking defense (API3); request.idempotencyKey replay/double-submit defense (API6); and capability wiring for the already-declared authentication.passwordPolicy / authentication.accountLockout enforcement (API2). v0.6 added: per-arg injection hardening (W19 request.schema.<f>.injectionGuard, attributed to the x-security-native SSEC-INJECTION category). v0.5 added: identity-flexibility (S-10 RuleRef namespaces: principal/session/header), outbound trust (S-11 outboundCalls), auth depth (S-12 mfa/lockout/passwordPolicy/tokenSources), error scrubbing (S-13), composite-ID semantics (S-14 identifier combinator), open-redirect (S-15 redirectAllowedDomains), session fixation (S-16 sessionRotateOnAuth), nonce replay (S-17 nonceCacheTtl), TLS floor (S-18 tls).",
25256
25256
  type: "object",
25257
25257
  additionalProperties: false,
25258
25258
  properties: {
@@ -25334,7 +25334,7 @@ var init_x_security_schema = __esm({
25334
25334
  pattern: "^API([1-9]|10):2023$"
25335
25335
  },
25336
25336
  SsecId: {
25337
- description: "Writ-native security category id for classes OWASP-API-2023 does not enumerate (Injection, LLM prompt-injection, audit logging, at-rest storage posture). Kept as a parallel pattern so the pure OWASP cells (^API([1-9]|10):2023$) cannot be overloaded or corrupted. v0.7 adds PROMPT (LLM prompt-injection) and AUDIT (audit logging) alongside INJECTION. v0.8 (deferred-residuals) adds STORAGE \u2014 an ADVISORY-ONLY at-rest posture class (encrypted/hashed/tokenized declaration). STORAGE is structurally unreachable by the gateway (it never sees the DB write); it NEVER compiles to enforcement and its capability is hard-pinned override-only/unsupported on every target. It exists only to document declared posture and drive an out-of-band scan finding.",
25337
+ description: "x-security-native security category id for classes OWASP-API-2023 does not enumerate (Injection, LLM prompt-injection, audit logging, at-rest storage posture). Kept as a parallel pattern so the pure OWASP cells (^API([1-9]|10):2023$) cannot be overloaded or corrupted. v0.7 adds PROMPT (LLM prompt-injection) and AUDIT (audit logging) alongside INJECTION. v0.8 (deferred-residuals) adds STORAGE \u2014 an ADVISORY-ONLY at-rest posture class (encrypted/hashed/tokenized declaration). STORAGE is structurally unreachable by the gateway (it never sees the DB write); it NEVER compiles to enforcement and its capability is hard-pinned override-only/unsupported on every target. It exists only to document declared posture and drive an out-of-band scan finding.",
25338
25338
  type: "string",
25339
25339
  pattern: "^SSEC-(INJECTION|PROMPT|AUDIT|STORAGE)$"
25340
25340
  },
@@ -25797,7 +25797,7 @@ var init_x_security_schema = __esm({
25797
25797
  type: "boolean"
25798
25798
  },
25799
25799
  injectionGuard: {
25800
- description: "v0.6 W19 (v0.7 adds 'deserialization' + 'ai-prompt'): opt-in per-arg injection hardening. Declares which injection sink(s) this body/query field flows into so the ModSecurity-family targets (coraza, bunkerweb) emit a native operator on ARGS:<field>|ARGS:json.<field> (covers both query/form args and the JSON body): 'sql' \u2192 @detectSQLi, 'nosql' \u2192 $where/$ne/$gt/$regex operator-token denylist, 'os-command' \u2192 shell-metacharacter @rx denylist ([;&|`$(){}<>] / newline), 'xpath' \u2192 XPath-metacharacter denylist, 'ldap' \u2192 LDAP-special-char denylist, 'code-eval' \u2192 eval/exec-marker denylist, 'xss' \u2192 @detectXSS (native cross-site-scripting operator), 'deserialization' \u2192 unsafe-deserialization preamble denylist (node-serialize _$$ND_FUNC$$_, Java rO0 base64, PHP O:<n>:, python pickle \\x80 opcode framing), 'ai-prompt' \u2192 LLM prompt-injection heuristic denylist (jailbreak / system-prompt-leak / role-override markers). Per-arg and explicit \u2014 replaces the implicit string-type heuristic. 'sql'/'nosql'/'os-command'/'xpath'/'ldap'/'code-eval'/'xss'/'deserialization' are attributed to SSEC-INJECTION; 'ai-prompt' is attributed to the distinct Writ-native SSEC-PROMPT class (one synthetic id per threat class). Never an OWASP-API cell. Edge-enforceable on coraza/bunkerweb only; kong/envoy resolve unsupported.",
25800
+ description: "v0.6 W19 (v0.7 adds 'deserialization' + 'ai-prompt'): opt-in per-arg injection hardening. Declares which injection sink(s) this body/query field flows into so the ModSecurity-family targets (coraza, bunkerweb) emit a native operator on ARGS:<field>|ARGS:json.<field> (covers both query/form args and the JSON body): 'sql' \u2192 @detectSQLi, 'nosql' \u2192 $where/$ne/$gt/$regex operator-token denylist, 'os-command' \u2192 shell-metacharacter @rx denylist ([;&|`$(){}<>] / newline), 'xpath' \u2192 XPath-metacharacter denylist, 'ldap' \u2192 LDAP-special-char denylist, 'code-eval' \u2192 eval/exec-marker denylist, 'xss' \u2192 @detectXSS (native cross-site-scripting operator), 'deserialization' \u2192 unsafe-deserialization preamble denylist (node-serialize _$$ND_FUNC$$_, Java rO0 base64, PHP O:<n>:, python pickle \\x80 opcode framing), 'ai-prompt' \u2192 LLM prompt-injection heuristic denylist (jailbreak / system-prompt-leak / role-override markers). Per-arg and explicit \u2014 replaces the implicit string-type heuristic. 'sql'/'nosql'/'os-command'/'xpath'/'ldap'/'code-eval'/'xss'/'deserialization' are attributed to SSEC-INJECTION; 'ai-prompt' is attributed to the distinct x-security-native SSEC-PROMPT class (one synthetic id per threat class). Never an OWASP-API cell. Edge-enforceable on coraza/bunkerweb only; kong/envoy resolve unsupported.",
25801
25801
  type: "array",
25802
25802
  minItems: 1,
25803
25803
  uniqueItems: true,
@@ -25878,7 +25878,7 @@ var init_x_security_schema = __esm({
25878
25878
  }
25879
25879
  },
25880
25880
  DataAtRest: {
25881
- description: "v0.8 (deferred-residuals, SSEC-STORAGE): ADVISORY-DECLARATION ONLY. Names body fields (e.g. password, pan, cvv, apiKey) and the asserted at-rest protection posture the app is SUPPOSED to apply. This field is NOT gateway-enforced and compiles to NOTHING enforcing \u2014 the gateway structurally never sees the DB write, so it cannot encrypt/hash/tokenize at rest. Its capability is HARD-PINNED to override-only/unsupported on EVERY target (never full, never partial). It exists ONLY to (1) document declared posture as a comment/annotation in the compiled output, and (2) drive an out-of-band Writ SCAN/agent finding under SSEC-STORAGE when the declared posture is absent or contradicted by detected plaintext storage. A finding, not a control.",
25881
+ description: "v0.8 (deferred-residuals, SSEC-STORAGE): ADVISORY-DECLARATION ONLY. Names body fields (e.g. password, pan, cvv, apiKey) and the asserted at-rest protection posture the app is SUPPOSED to apply. This field is NOT gateway-enforced and compiles to NOTHING enforcing \u2014 the gateway structurally never sees the DB write, so it cannot encrypt/hash/tokenize at rest. Its capability is HARD-PINNED to override-only/unsupported on EVERY target (never full, never partial). It exists ONLY to (1) document declared posture as a comment/annotation in the compiled output, and (2) drive an out-of-band x-security SCAN/agent finding under SSEC-STORAGE when the declared posture is absent or contradicted by detected plaintext storage. A finding, not a control.",
25882
25882
  type: "object",
25883
25883
  required: ["fields", "protection"],
25884
25884
  additionalProperties: false,
@@ -25898,7 +25898,7 @@ var init_x_security_schema = __esm({
25898
25898
  }
25899
25899
  },
25900
25900
  Logging: {
25901
- description: "v0.7 (SSEC-AUDIT): declarative audit/access logging policy. The gateway IS the log point, so this compiles natively per target: coraza SecAuditLog/SecAuditLogParts + per-event tagged log actions, bunkerweb modsec audit config, kong http-log/file-log/tcp-log plugins, envoy access_log with a JSON format string. Writ-native (OWASP-API-2023 retired the dedicated logging class, so this is attributed to SSEC-AUDIT, never an API cell).",
25901
+ description: "v0.7 (SSEC-AUDIT): declarative audit/access logging policy. The gateway IS the log point, so this compiles natively per target: coraza SecAuditLog/SecAuditLogParts + per-event tagged log actions, bunkerweb modsec audit config, kong http-log/file-log/tcp-log plugins, envoy access_log with a JSON format string. x-security-native (OWASP-API-2023 retired the dedicated logging class, so this is attributed to SSEC-AUDIT, never an API cell).",
25902
25902
  type: "object",
25903
25903
  required: ["events"],
25904
25904
  additionalProperties: false,
@@ -26129,7 +26129,7 @@ var init_x_security_schema = __esm({
26129
26129
  }
26130
26130
  },
26131
26131
  GraphqlOperation: {
26132
- description: "v0.8 (deferred-residuals): per-OPERATION GraphQL policy bound to a single named field/operation (e.g. systemDiagnostics, pastes, importPaste) that the one POST /graphql route funnels. authz reuses the Authorization rule grammar (rule-based jwt.sub==resource.owner for per-resolver BOLA \u2192 API1:2023; rbac for per-resolver BFLA \u2192 API5:2023). Per-operation maxDepth/maxComplexity/maxAliases override the block-level coarse limits (API4:2023). OVERRIDE-ONLY on every target: a gateway physically cannot evaluate per-resolver authz or per-operation cost without parsing the GraphQL query+variables out of the POST body and resolving the selection set \u2014 the SAME GraphQL-aware-processor gap as the response-schema ext_proc. Writ ships SCAFFOLDING (an ext_proc filter + a graphql-operations.json data file and/or a graphql-armor/Apollo-router config artifact); ENFORCEMENT DEPENDS ON the operator supplying the GraphQL-aware processor. Until they do, NOTHING here is enforced \u2014 therefore override-only, NOT full, NOT partial. The compiled artifact's enforcement status reads 'override-only' verbatim.",
26132
+ description: "v0.8 (deferred-residuals): per-OPERATION GraphQL policy bound to a single named field/operation (e.g. systemDiagnostics, pastes, importPaste) that the one POST /graphql route funnels. authz reuses the Authorization rule grammar (rule-based jwt.sub==resource.owner for per-resolver BOLA \u2192 API1:2023; rbac for per-resolver BFLA \u2192 API5:2023). Per-operation maxDepth/maxComplexity/maxAliases override the block-level coarse limits (API4:2023). OVERRIDE-ONLY on every target: a gateway physically cannot evaluate per-resolver authz or per-operation cost without parsing the GraphQL query+variables out of the POST body and resolving the selection set \u2014 the SAME GraphQL-aware-processor gap as the response-schema ext_proc. x-security ships SCAFFOLDING (an ext_proc filter + a graphql-operations.json data file and/or a graphql-armor/Apollo-router config artifact); ENFORCEMENT DEPENDS ON the operator supplying the GraphQL-aware processor. Until they do, NOTHING here is enforced \u2014 therefore override-only, NOT full, NOT partial. The compiled artifact's enforcement status reads 'override-only' verbatim.",
26133
26133
  type: "object",
26134
26134
  required: ["name"],
26135
26135
  additionalProperties: false,
@@ -26145,7 +26145,7 @@ var init_x_security_schema = __esm({
26145
26145
  enum: ["query", "mutation", "subscription"]
26146
26146
  },
26147
26147
  authz: {
26148
- description: "Per-resolver authorization. Mirrors the top-level Authorization $def grammar (rbac / rule-based / abac). Presence attributes to API1:2023 (per-resolver BOLA) and API5:2023 (per-resolver BFLA). OVERRIDE-ONLY \u2014 requires an operator-supplied GraphQL-aware processor; Writ emits only the rule data + scaffolding, never an enforcing filter.",
26148
+ description: "Per-resolver authorization. Mirrors the top-level Authorization $def grammar (rbac / rule-based / abac). Presence attributes to API1:2023 (per-resolver BOLA) and API5:2023 (per-resolver BFLA). OVERRIDE-ONLY \u2014 requires an operator-supplied GraphQL-aware processor; x-security emits only the rule data + scaffolding, never an enforcing filter.",
26149
26149
  $ref: "#/$defs/Authorization"
26150
26150
  },
26151
26151
  maxDepth: { type: "integer", minimum: 1, maximum: 50 },
@@ -26326,19 +26326,19 @@ var init_owasp_mapping = __esm({
26326
26326
  mitigatedBy: ["mtls", "request.schema.domainAllowlist", "request.signature", "request.allowedHosts"]
26327
26327
  },
26328
26328
  "SSEC-INJECTION": {
26329
- name: "Injection (Writ-native)",
26329
+ name: "Injection (x-security-native)",
26330
26330
  mitigatedBy: ["request.schema.injectionGuard"]
26331
26331
  },
26332
26332
  "SSEC-PROMPT": {
26333
- name: "LLM Prompt Injection (Writ-native)",
26333
+ name: "LLM Prompt Injection (x-security-native)",
26334
26334
  mitigatedBy: ["request.schema.injectionGuard"]
26335
26335
  },
26336
26336
  "SSEC-AUDIT": {
26337
- name: "Audit Logging (Writ-native)",
26337
+ name: "Audit Logging (x-security-native)",
26338
26338
  mitigatedBy: ["logging"]
26339
26339
  },
26340
26340
  "SSEC-STORAGE": {
26341
- name: "At-Rest Storage Posture (Writ-native, advisory-only)",
26341
+ name: "At-Rest Storage Posture (x-security-native, advisory-only)",
26342
26342
  mitigatedBy: ["request.dataAtRest"]
26343
26343
  }
26344
26344
  };
@@ -62903,7 +62903,7 @@ ${plan.yaml}`,
62903
62903
  endpoint: "(gateway)",
62904
62904
  rule: "load-coverage",
62905
62905
  verdict: "FAIL",
62906
- message: "Writ-emitted artifacts are not loaded by the gateway (lazy verify reported <90%). Aborting traffic phase \u2014 the results would be unattributable.",
62906
+ message: "x-security-emitted artifacts are not loaded by the gateway (xsecurity verify reported <90%). Aborting traffic phase \u2014 the results would be unattributable.",
62907
62907
  durationMs: 0
62908
62908
  });
62909
62909
  } else {
@@ -63296,7 +63296,7 @@ var init_feasibility = __esm({
63296
63296
  ]
63297
63297
  };
63298
63298
  CAPKEY_DISCLAIMERS = {
63299
- "graphql.operations.authz": "override-only: per-operation GraphQL authz enforcement depends on an operator-supplied GraphQL-aware processor; Writ emits scaffolding only",
63299
+ "graphql.operations.authz": "override-only: per-operation GraphQL authz enforcement depends on an operator-supplied GraphQL-aware processor; x-security emits scaffolding only",
63300
63300
  "graphql.staticLimits": "override-only: coarse GraphQL cost limits depend on an operator-supplied GraphQL-aware processor; a non-parsing crude limit is partial at best",
63301
63301
  "request.serializeBy": "edge serialization only \u2014 does NOT provide in-handler transaction atomicity",
63302
63302
  "request.dataAtRest": "advisory posture declaration \u2014 NOT gateway-enforced; drives an out-of-band SSEC-STORAGE scan finding"
@@ -64034,7 +64034,7 @@ async function checkEndpoint(input, fetcher = defaultFetcher) {
64034
64034
  const res = await fetcher(url, {
64035
64035
  headers: {
64036
64036
  Authorization: `Bearer ${apiKey}`,
64037
- "User-Agent": "@writ/cursor-mcp/0.1.0",
64037
+ "User-Agent": "@x-security/cursor-mcp/0.1.0",
64038
64038
  Accept: "application/json"
64039
64039
  }
64040
64040
  });
@@ -64276,7 +64276,7 @@ async function runMcp() {
64276
64276
  const mod = await Promise.resolve().then(() => (init_dist5(), dist_exports));
64277
64277
  const main2 = mod.main ?? mod.default;
64278
64278
  if (typeof main2 !== "function") {
64279
- throw new Error("@writ/cursor-mcp did not export a main()/default function");
64279
+ throw new Error("@x-security/cursor-mcp did not export a main()/default function");
64280
64280
  }
64281
64281
  await main2();
64282
64282
  return { exitCode: 0 };
@@ -67839,7 +67839,7 @@ function flaskMethods(tail) {
67839
67839
  return verbs.length > 0 ? verbs : ["GET"];
67840
67840
  }
67841
67841
  function stripPyComments(text) {
67842
- return text.split("\n").filter((line) => !line.trimStart().startsWith("#")).join("\n");
67842
+ return text.split("\n").map((line) => line.trimStart().startsWith("#") ? "" : line).join("\n");
67843
67843
  }
67844
67844
  function lineAt(text, index) {
67845
67845
  let line = 1;
@@ -68970,7 +68970,7 @@ function lineAt8(text, index) {
68970
68970
  return line;
68971
68971
  }
68972
68972
  function stripPyComments4(text) {
68973
- return text.split("\n").filter((line) => !line.trimStart().startsWith("#")).join("\n");
68973
+ return text.split("\n").map((line) => line.trimStart().startsWith("#") ? "" : line).join("\n");
68974
68974
  }
68975
68975
  async function parseGraphene(repoDir) {
68976
68976
  const routes = [];
@@ -69038,8 +69038,8 @@ function opBlockRe(type) {
69038
69038
  return new RegExp(`type\\s+${type}\\s*\\{([^}]*)\\}`, "g");
69039
69039
  }
69040
69040
  function stripJsComments(text) {
69041
- const noBlocks = text.replace(/\/\*[\s\S]*?\*\//g, "");
69042
- return noBlocks.split("\n").filter((line) => !line.trimStart().startsWith("//")).join("\n");
69041
+ const noBlocks = text.replace(/\/\*[\s\S]*?\*\//g, (m3) => m3.replace(/[^\n]/g, " "));
69042
+ return noBlocks.split("\n").map((line) => line.trimStart().startsWith("//") ? "" : line).join("\n");
69043
69043
  }
69044
69044
  function lineAt9(text, index) {
69045
69045
  let line = 1;
@@ -69150,15 +69150,19 @@ function lineAt10(text, index) {
69150
69150
  function stripComments2(text, lang) {
69151
69151
  let t = text;
69152
69152
  if (lang === "js") {
69153
- t = t.replace(/\/\*[\s\S]*?\*\//g, "");
69153
+ t = t.replace(/\/\*[\s\S]*?\*\//g, (m3) => m3.replace(/[^\n]/g, " "));
69154
69154
  }
69155
69155
  const out = [];
69156
69156
  for (let line of t.split("\n")) {
69157
69157
  const s = line.trimStart();
69158
- if (lang === "js" && s.startsWith("//"))
69158
+ if (lang === "js" && s.startsWith("//")) {
69159
+ out.push("");
69159
69160
  continue;
69160
- if (lang === "py" && s.startsWith("#"))
69161
+ }
69162
+ if (lang === "py" && s.startsWith("#")) {
69163
+ out.push("");
69161
69164
  continue;
69165
+ }
69162
69166
  if (lang === "js") {
69163
69167
  line = line.replace(/(^|[^:'"])\/\/.*$/, "$1");
69164
69168
  }
@@ -73141,7 +73145,7 @@ var init_push = __esm({
73141
73145
  DEFAULT_API_URL2 = "https://usewaf.com";
73142
73146
  HOST_ALLOWLIST_SUFFIXES = [".chain305.com", ".lazy.chain305.com"];
73143
73147
  LOCAL_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
73144
- USER_AGENT = "@writ/cli push";
73148
+ USER_AGENT = "@x-security/cli push";
73145
73149
  REPO_URL_RE = /^https:\/\/github\.com\/[^/\s]+\/[^/\s]+(\.git)?$/i;
73146
73150
  PushError = class extends Error {
73147
73151
  };
@@ -73436,7 +73440,7 @@ var init_ci_gate = __esm({
73436
73440
  "#!/usr/bin/env bash",
73437
73441
  "# Fail CI if any emitted control lost its byte-matching citation (Rule D-3).",
73438
73442
  "set -euo pipefail",
73439
- 'OUT="$(npx --yes @writ/cli audit .)"',
73443
+ 'OUT="$(npx --yes @x-security/cli audit .)"',
73440
73444
  'echo "$OUT"',
73441
73445
  `CITE_BACKED="$(printf '%s' "$OUT" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>process.stdout.write(String(JSON.parse(s).citeBacked)))')"`,
73442
73446
  'if [ "$CITE_BACKED" != "true" ]; then',
@@ -75247,7 +75251,7 @@ Examples:
75247
75251
  process.exit(1);
75248
75252
  }
75249
75253
  });
75250
- program.command("mcp").description("Run the Writ Cursor MCP server (stdio JSON-RPC). For use in .cursor/mcp.json.").action(async () => {
75254
+ program.command("mcp").description("Run the x-security Cursor MCP server (stdio JSON-RPC). For use in .cursor/mcp.json.").action(async () => {
75251
75255
  try {
75252
75256
  const r5 = await runMcp();
75253
75257
  process.exit(r5.exitCode);
@@ -75257,7 +75261,7 @@ Examples:
75257
75261
  process.exit(1);
75258
75262
  }
75259
75263
  });
75260
- program.command("verify-bundle <tarball>").description("Verify a signed Writ release bundle (sha256 file hashes + Ed25519 manifest signature).").option("--public-key <path>", "Path to an Ed25519 SPKI PEM public key. Defaults to the embedded release key.").action(async (tarball, opts) => {
75264
+ program.command("verify-bundle <tarball>").description("Verify a signed x-security release bundle (sha256 file hashes + Ed25519 manifest signature).").option("--public-key <path>", "Path to an Ed25519 SPKI PEM public key. Defaults to the embedded release key.").action(async (tarball, opts) => {
75261
75265
  try {
75262
75266
  const verifyOpts = {};
75263
75267
  if (opts.publicKey !== void 0) verifyOpts.publicKeyPath = opts.publicKey;
@@ -75314,7 +75318,7 @@ Examples:
75314
75318
  });
75315
75319
  registerExtras(program);
75316
75320
  program.command("push <repoDir>").description(
75317
- "Upload the verified .writ/ policies to the Writ SaaS. Aborts if the local audit is not 100% cite-backed. Token from WRIT_API_TOKEN env only."
75321
+ "Upload the verified .writ/ policies to the x-security SaaS. Aborts if the local audit is not 100% cite-backed. Token from WRIT_API_TOKEN env only."
75318
75322
  ).option("--dry-run", "Assemble + validate the payload and print a summary WITHOUT sending.").action(async (repoDir, opts) => {
75319
75323
  try {
75320
75324
  const pushOpts = {};
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "@chain305/x-security",
3
- "version": "0.2.1",
4
- "description": "Writ CLI — generate/validate/test/report/diff/init against multiple gateway targets",
3
+ "version": "0.2.3",
4
+ "description": "x-security CLI — generate/validate/test/report/diff/init against multiple gateway targets",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://usewaf.com",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/ZeeshanDarasa/specshield.git",
10
- "directory": "packages/cli"
9
+ "url": "git+https://github.com/ZeeshanSultan/x-security.git"
11
10
  },
12
11
  "type": "module",
13
12
  "bin": {