deepdebug-local-agent 1.0.23 → 1.2.0

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.
Files changed (178) hide show
  1. package/.claude/context.md +76 -0
  2. package/.claude/skills/README.md +25 -0
  3. package/.claude/skills/tdd-debugging/SKILL.md +53 -0
  4. package/.claude/skills/tdd-debugging/references/anti-patterns.md +43 -0
  5. package/.claude/skills/tdd-debugging/references/command-reference.md +46 -0
  6. package/.claude/standards/README.md +51 -0
  7. package/.claude/standards/clean-code.md +75 -0
  8. package/.claude/standards/code-review-checklist.md +61 -0
  9. package/.claude/standards/layered-architecture.md +163 -0
  10. package/.claude/standards/node.md +45 -0
  11. package/.claude/standards/security-owasp.md +114 -0
  12. package/.claude/standards/simplicity.md +42 -0
  13. package/.claude/standards/solid.md +64 -0
  14. package/.claude/standards/testing.md +59 -0
  15. package/.cursor/rules/standards.mdc +17 -0
  16. package/.github/workflows/build-byoc-image.yml +315 -0
  17. package/.github/workflows/deploy-gcp.yml +102 -0
  18. package/.github/workflows/npm-publish.yml +76 -8
  19. package/AGENTS.md +21 -0
  20. package/CHANGELOG.md +76 -0
  21. package/CLAUDE.md +13 -0
  22. package/CLAUDE_CODE_AGENT_INFINITE.md +5 -3
  23. package/Dockerfile +4 -0
  24. package/Dockerfile.full +55 -3
  25. package/bin/install.js +16 -5
  26. package/cloudbuild-full.yaml +57 -0
  27. package/docker-compose.yml +5 -3
  28. package/docs/OBSERVABILITY.md +164 -0
  29. package/docs/byoc-agent-image.md +70 -0
  30. package/docs/dlp.md +78 -0
  31. package/docs/graphify-packaging-plan.md +133 -0
  32. package/docs/graphify-validation-run-2026-10-28.md +243 -0
  33. package/docs/releasing.md +37 -0
  34. package/docs/signed-commands.md +163 -0
  35. package/env.example +34 -0
  36. package/helm/Chart.yaml +2 -2
  37. package/helm/templates/deployment.yaml +13 -3
  38. package/helm/templates/networkpolicy.yaml +22 -0
  39. package/helm/templates/secret.yaml +1 -0
  40. package/helm/values.yaml +13 -14
  41. package/mcp-server.js +4 -1
  42. package/package.json +9 -4
  43. package/scripts/next-version.mjs +75 -0
  44. package/scripts/upgrade-observability-push.sh +227 -0
  45. package/src/ai-engine.js +22 -22
  46. package/src/config/trusted-signing-keys.json +3 -0
  47. package/src/detectors/build-tool-detector.js +50 -0
  48. package/src/detectors/multi-project-detector.js +22 -22
  49. package/src/detectors/service-detector.js +24 -24
  50. package/src/dlp/engine.js +111 -0
  51. package/src/dlp/index.js +137 -0
  52. package/src/dlp/rules.js +97 -0
  53. package/src/dlp/validators.js +123 -0
  54. package/src/exec-utils.js +26 -4
  55. package/src/git/base-git-provider.js +117 -117
  56. package/src/git/bitbucket-provider.js +2 -2
  57. package/src/git/git-provider-registry.js +18 -18
  58. package/src/git/github-provider.js +13 -13
  59. package/src/git/multi-repo-pr.js +161 -0
  60. package/src/mcp-http-server.js +32 -16
  61. package/src/observability/bundle-files.js +418 -0
  62. package/src/observability/detect.js +151 -0
  63. package/src/observability/provision.js +212 -0
  64. package/src/observability/render-cli.js +59 -0
  65. package/src/observability/routes.js +88 -0
  66. package/src/patch/patch-engine.js +28 -28
  67. package/src/patch-manager.js +85 -85
  68. package/src/patch_bkp.js +14 -14
  69. package/src/ports.js +4 -4
  70. package/src/routes/workspace.route.js +47 -16
  71. package/src/runtimes/base-runtime.js +75 -75
  72. package/src/runtimes/java/gradle-runtime.js +17 -17
  73. package/src/runtimes/java/java-integrations.js +25 -25
  74. package/src/runtimes/java/maven-runtime.js +34 -34
  75. package/src/runtimes/node/node-integrations.js +1 -1
  76. package/src/runtimes/node/npm-runtime.js +14 -14
  77. package/src/runtimes/node/yarn-runtime.js +4 -4
  78. package/src/runtimes/runtime-registry.js +25 -25
  79. package/src/server-local.js +4 -4
  80. package/src/server.js +1366 -333
  81. package/src/siblings/burst-suppressor.js +89 -0
  82. package/src/siblings/capabilities.js +273 -0
  83. package/src/siblings/env-compat.cjs +58 -0
  84. package/src/siblings/incident-forwarder.js +322 -0
  85. package/src/siblings/logger.js +15 -0
  86. package/src/siblings/metrics.js +94 -0
  87. package/src/utils/agent-auth.js +184 -0
  88. package/src/utils/approval-token.js +56 -0
  89. package/src/utils/bind-host.js +29 -0
  90. package/src/utils/branch-refspec.js +98 -0
  91. package/src/utils/child-env.js +34 -0
  92. package/src/utils/environment-diagnostics.js +55 -55
  93. package/src/utils/exec-policy.js +962 -0
  94. package/src/utils/exec-utils.js +15 -15
  95. package/src/utils/file-count.js +46 -0
  96. package/src/utils/fs-utils.js +10 -10
  97. package/src/utils/multi-repo-open.js +132 -0
  98. package/src/utils/open-gate.js +183 -0
  99. package/src/utils/ranged-read.js +65 -0
  100. package/src/utils/request-guards.js +77 -0
  101. package/src/utils/request-signing.js +342 -0
  102. package/src/utils/root-recovery.js +244 -0
  103. package/src/utils/safe-exec-args.js +58 -0
  104. package/src/utils/sandbox.js +182 -0
  105. package/src/utils/search-outcome.js +56 -0
  106. package/src/utils/workspace-root.js +80 -0
  107. package/src/validators/syntax-validator.js +149 -0
  108. package/src/workspace/detect-port.js +16 -16
  109. package/src/workspace/file-reader.js +1 -1
  110. package/src/workspace/process-manager.js +46 -46
  111. package/src/workspace-manager.js +86 -24
  112. package/test/adapters/registry.test.js +9 -2
  113. package/test/agent-auth.test.js +194 -0
  114. package/test/bind-host.test.js +26 -0
  115. package/test/branch-refspec.test.js +224 -0
  116. package/test/burst-suppressor.test.js +60 -0
  117. package/test/capabilities-access.test.js +47 -0
  118. package/test/capabilities.test.js +87 -0
  119. package/test/child-env.test.js +23 -0
  120. package/test/dlp/engine.test.js +173 -0
  121. package/test/dlp/fixtures.js +126 -0
  122. package/test/dlp/index.test.js +166 -0
  123. package/test/env-compat.test.js +71 -0
  124. package/test/exec-policy.test.js +463 -0
  125. package/test/file-count.test.js +64 -0
  126. package/test/incident-forwarder.test.js +231 -0
  127. package/test/multi-repo-open.test.js +180 -0
  128. package/test/multi-repo-pr.test.js +129 -0
  129. package/test/next-version.test.js +48 -0
  130. package/test/observability-detect.test.js +199 -0
  131. package/test/open-gate.test.js +341 -0
  132. package/test/ranged-read.test.js +60 -0
  133. package/test/request-guards.test.js +91 -0
  134. package/test/request-signing.test.js +284 -0
  135. package/test/root-recovery-sidecar.test.js +171 -0
  136. package/test/root-recovery.test.js +274 -0
  137. package/test/safe-exec-args.test.js +58 -0
  138. package/test/sandbox.test.js +98 -0
  139. package/test/search-outcome.test.js +50 -0
  140. package/test/workspace-root.test.js +64 -0
  141. package/tools/graphify-validation/README.md +92 -0
  142. package/tools/graphify-validation/config/questions.json +31 -0
  143. package/tools/graphify-validation/config/repos.json +9 -0
  144. package/tools/graphify-validation/config/symbols.json +6 -0
  145. package/tools/graphify-validation/fixtures/spring/expected.json +34 -0
  146. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/AppConfig.java +29 -0
  147. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/AuditLogger.java +15 -0
  148. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/Cache.java +7 -0
  149. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/CheckoutService.java +25 -0
  150. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/InMemoryCache.java +18 -0
  151. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/OrderController.java +22 -0
  152. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/PaymentGateway.java +5 -0
  153. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/PaypalGateway.java +11 -0
  154. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/RefundService.java +14 -0
  155. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/StripeGateway.java +11 -0
  156. package/tools/graphify-validation/lib/affected_vs_rg.py +81 -0
  157. package/tools/graphify-validation/lib/audit_hook/sitecustomize.py +22 -0
  158. package/tools/graphify-validation/lib/graph_metrics.py +96 -0
  159. package/tools/graphify-validation/lib/gv_common.py +130 -0
  160. package/tools/graphify-validation/lib/licenses.py +47 -0
  161. package/tools/graphify-validation/lib/pip_audit_summary.py +18 -0
  162. package/tools/graphify-validation/lib/recall.py +115 -0
  163. package/tools/graphify-validation/lib/report.py +226 -0
  164. package/tools/graphify-validation/lib/run_all.py +237 -0
  165. package/tools/graphify-validation/lib/run_graphify.py +144 -0
  166. package/tools/graphify-validation/lib/rusage_helper.py +17 -0
  167. package/tools/graphify-validation/lib/sample_edges.py +246 -0
  168. package/tools/graphify-validation/lib/spring_fixture.py +81 -0
  169. package/tools/graphify-validation/requirements-py311.lock +508 -0
  170. package/tools/graphify-validation/requirements-tools.in +1 -0
  171. package/tools/graphify-validation/requirements-tools.lock +371 -0
  172. package/tools/graphify-validation/requirements.in +1 -0
  173. package/tools/graphify-validation/requirements.lock +502 -0
  174. package/tools/graphify-validation/run.sh +43 -0
  175. package/tools/graphify-validation/tests/test_harness.py +151 -0
  176. package/cloudbuild-agent-qa.yaml +0 -43
  177. package/cloudbuild-agent-staging.yaml +0 -40
  178. package/cloudbuild.yaml.deprecated +0 -42
@@ -0,0 +1,97 @@
1
+ /**
2
+ * DLP ruleset (versioned). Each rule: { id, class, re, group?, validate? }.
3
+ * - id: stable identifier, used as the metric label and in the placeholder.
4
+ * - class: coarse family, used by LOCAL_AGENT_DLP_BLOCK_CLASSES.
5
+ * - re: global regex (the engine resets lastIndex; never share state).
6
+ * - group: capture group to redact; default is the whole match.
7
+ * - validate: optional predicate on the redactable text; false = not a hit.
8
+ *
9
+ * Order matters: specific rules run before generic ones, so a Stripe key is
10
+ * reported as stripe_key and not as a generic secret assignment.
11
+ * Bump RULESET_VERSION on every change to the list or to a pattern.
12
+ *
13
+ * Reimplemented from public token formats; no third-party rule files copied.
14
+ */
15
+ import {
16
+ looksLikeLiteralSecret, looksLikeOpaqueKey, realEmail, plausiblePhone,
17
+ plausibleCard, ibanValid, ptNifValid,
18
+ } from './validators.js';
19
+
20
+ export const RULESET_VERSION = '2026.10.28-1';
21
+
22
+ export const RULE_CLASSES = Object.freeze([
23
+ 'private-key', 'cloud-credential', 'vcs-token', 'payment-key', 'saas-token', 'token',
24
+ 'credential', 'connection-string', 'url-credential', 'pii-email', 'pii-phone', 'pii-id',
25
+ 'pii-financial', 'high-entropy',
26
+ ]);
27
+
28
+ const r = (id, cls, re, extra = {}) => Object.freeze({ id, class: cls, re, ...extra });
29
+
30
+ export const RULES = Object.freeze([
31
+ // Private keys first: they span lines and may contain other-looking text.
32
+ r('pem_private_key', 'private-key',
33
+ /-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----[\s\S]*?(?:-----END (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----|$)/g),
34
+
35
+ // Cloud
36
+ r('aws_access_key_id', 'cloud-credential', /\b(?:AKIA|ASIA|AGPA|AIDA|AROA|ANPA|ANVA|AIPA)[A-Z0-9]{16}\b/g),
37
+ r('aws_secret_access_key', 'cloud-credential',
38
+ /\baws[_-]?secret[_-]?(?:access[_-]?)?key["']?\s*[:=]\s*["']?([A-Za-z0-9/+=]{40})\b/gi, { group: 1 }),
39
+ r('gcp_api_key', 'cloud-credential', /\bAIza[0-9A-Za-z_-]{35}\b/g),
40
+ r('gcp_oauth_token', 'cloud-credential', /\bya29\.[0-9A-Za-z_-]{20,}/g),
41
+ r('gcp_oauth_client_secret', 'cloud-credential', /\bGOCSPX-[A-Za-z0-9_-]{20,}/g),
42
+ r('azure_storage_account_key', 'cloud-credential', /\bAccountKey=([A-Za-z0-9+/]{40,}={0,2})/g, { group: 1 }),
43
+ r('digitalocean_token', 'cloud-credential', /\bdo[opr]_v1_[a-f0-9]{64}\b/g),
44
+
45
+ // VCS / package registries
46
+ r('github_token', 'vcs-token', /\bgh[pousr]_[A-Za-z0-9]{36,}\b/g),
47
+ r('github_fine_grained_pat', 'vcs-token', /\bgithub_pat_[A-Za-z0-9_]{22,}\b/g),
48
+ r('gitlab_pat', 'vcs-token', /\bglpat-[A-Za-z0-9_-]{20,}/g),
49
+ r('npm_token', 'vcs-token', /\bnpm_[A-Za-z0-9]{36}\b/g),
50
+ r('pypi_token', 'vcs-token', /\bpypi-AgEIcHlwaS5vcmc[A-Za-z0-9_-]{50,}/g),
51
+
52
+ // Payments / SaaS
53
+ r('stripe_key', 'payment-key', /\b[sr]k_(?:live|test)_[0-9A-Za-z]{16,}\b/g),
54
+ r('stripe_webhook_secret', 'payment-key', /\bwhsec_[A-Za-z0-9]{16,}\b/g),
55
+ r('shopify_token', 'saas-token', /\bshp(?:at|ca|pa|ss)_[a-f0-9]{32}\b/g),
56
+ r('slack_token', 'saas-token', /\bxox[abprs]-[A-Za-z0-9-]{10,}/g),
57
+ r('slack_webhook', 'saas-token', /https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]+/g),
58
+ r('discord_webhook', 'saas-token', /https:\/\/(?:discord|discordapp)\.com\/api\/webhooks\/\d+\/[\w-]+/g),
59
+ r('sendgrid_key', 'saas-token', /\bSG\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}/g),
60
+ r('twilio_api_key', 'saas-token', /\bSK[0-9a-f]{32}\b/g),
61
+ r('mailgun_key', 'saas-token', /\bkey-[0-9a-f]{32}\b/g),
62
+ r('huggingface_token', 'saas-token', /\bhf_[A-Za-z0-9]{34,}\b/g),
63
+ r('telegram_bot_token', 'saas-token', /\b\d{8,10}:AA[A-Za-z0-9_-]{33}\b/g),
64
+ r('anthropic_key', 'saas-token', /\bsk-ant-[A-Za-z0-9_-]{20,}/g),
65
+ r('openai_key', 'saas-token', /\bsk-(?:proj-)?[A-Za-z0-9_-]{32,}/g, { validate: (v) => /\d/.test(v) }),
66
+
67
+ // Generic tokens
68
+ r('jwt', 'token', /\beyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g),
69
+ r('bearer_token', 'token', /\bBearer\s+([A-Za-z0-9._~+/-]{20,}=*)/g, { group: 1 }),
70
+ r('basic_auth_header', 'token', /\bAuthorization:\s*Basic\s+([A-Za-z0-9+/]{12,}={0,2})/gi, { group: 1 }),
71
+
72
+ // Connection strings and URL credentials (before the generic assignment rule)
73
+ r('db_connection_string', 'connection-string',
74
+ /\b(?:postgres(?:ql)?|mysql|mariadb|mongodb(?:\+srv)?|redis|rediss|amqps?|mssql|sqlserver|cockroachdb):\/\/[^\s"'`<>]+/gi,
75
+ { validate: (v) => /:\/\/[^/\s]*@/.test(v) }),
76
+ r('jdbc_password', 'connection-string', /\bjdbc:[a-z0-9]+:[^\s"'`]*?[?&;](?:password|pwd)=([^\s&;"'`]+)/gi, { group: 1 }),
77
+ r('ado_connection_password', 'connection-string', /(?:^|;)\s*(?:Password|Pwd)\s*=\s*([^;\r\n"']{3,})/gim, { group: 1 }),
78
+ r('url_credentials', 'url-credential', /\b[a-z][a-z0-9+.-]{0,20}:\/\/([^\s:@/"'`<>]+:[^\s@/"'`<>]+)@/gi, { group: 1, validate: (v) => !/[${}<>]/.test(v) }),
79
+
80
+ // Generic "name = literal" assignments
81
+ r('generic_secret_assignment', 'credential',
82
+ /\b(?:[A-Za-z0-9_-]{0,40}?(?:password|passwd|pwd|secret|api[_-]?key|apikey|access[_-]?token|auth[_-]?token|client[_-]?secret|private[_-]?key|token))["']?\s*(?::|=|=>)\s*["']?([^\s"'`,;]{8,})/gi,
83
+ { group: 1, validate: looksLikeLiteralSecret }),
84
+
85
+ // PII
86
+ r('email', 'pii-email', /[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9-]{1,63}(?:\.[A-Za-z0-9-]{1,63}){0,6}\.[A-Za-z]{2,24}(?![A-Za-z0-9_~./-]|:[A-Za-z0-9_~./-])/g, { validate: realEmail }),
87
+ r('iban', 'pii-financial', /\b[A-Z]{2}\d{2}(?: ?[A-Z0-9]{4}){2,7}(?: ?[A-Z0-9]{1,3})?\b/g, { validate: ibanValid }),
88
+ r('credit_card', 'pii-financial', /(?<![\d.-])\d{4}(?:[ -]?\d{4}){2}[ -]?\d{1,7}(?![\d-])/g, { validate: plausibleCard }),
89
+ r('pt_nif', 'pii-id',
90
+ /\b(?:NIF|NIPC|contribuinte|VAT)\b\s*(?:n[.ºo°]*\s*)?[:=#-]?\s*(?:PT)?(\d{9})\b/gi, { group: 1, validate: ptNifValid }),
91
+ r('phone_international', 'pii-phone', /(?<![\w.+])(?:\+|00)\d{1,3}(?:[ .-]?\(?\d{1,4}\)?){2,5}(?![\w])/g,
92
+ { validate: plausiblePhone }),
93
+
94
+ // Last: opaque high-entropy blobs
95
+ r('high_entropy_blob', 'high-entropy', /(?<![A-Za-z0-9+/_=-])[A-Za-z0-9+/_=-]{40,}(?![A-Za-z0-9+/_=-])/g,
96
+ { validate: looksLikeOpaqueKey }),
97
+ ]);
@@ -0,0 +1,123 @@
1
+ /**
2
+ * DLP validators: pure helpers that cut false positives after a regex matched.
3
+ * No I/O, no state.
4
+ */
5
+
6
+ /** Shannon entropy in bits per character. */
7
+ export function shannonEntropy(s) {
8
+ if (!s) return 0;
9
+ const freq = new Map();
10
+ for (const ch of s) freq.set(ch, (freq.get(ch) || 0) + 1);
11
+ let h = 0;
12
+ for (const n of freq.values()) {
13
+ const p = n / s.length;
14
+ h -= p * Math.log2(p);
15
+ }
16
+ return h;
17
+ }
18
+
19
+ /** Luhn checksum over a digit string. */
20
+ export function luhnValid(digits) {
21
+ if (!/^\d{13,19}$/.test(digits)) return false;
22
+ let sum = 0;
23
+ let alt = false;
24
+ for (let i = digits.length - 1; i >= 0; i--) {
25
+ let d = digits.charCodeAt(i) - 48;
26
+ if (alt) {
27
+ d *= 2;
28
+ if (d > 9) d -= 9;
29
+ }
30
+ sum += d;
31
+ alt = !alt;
32
+ }
33
+ return sum % 10 === 0;
34
+ }
35
+
36
+ /** ISO 13616 mod-97 check for an IBAN (spaces allowed). */
37
+ export function ibanValid(raw) {
38
+ const s = raw.replace(/\s+/g, '').toUpperCase();
39
+ if (!/^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/.test(s)) return false;
40
+ const rearranged = s.slice(4) + s.slice(0, 4);
41
+ let rem = 0;
42
+ for (const ch of rearranged) {
43
+ const v = ch >= 'A' && ch <= 'Z' ? String(ch.charCodeAt(0) - 55) : ch;
44
+ for (const c of v) rem = (rem * 10 + (c.charCodeAt(0) - 48)) % 97;
45
+ }
46
+ return rem === 1;
47
+ }
48
+
49
+ /** Portuguese NIF/NIPC checksum (9 digits, mod 11). */
50
+ export function ptNifValid(digits) {
51
+ if (!/^\d{9}$/.test(digits)) return false;
52
+ const okPrefix = '1235689'.includes(digits[0]) || /^(?:45|70|71|72|74|75|77|79)/.test(digits);
53
+ if (!okPrefix) return false;
54
+ let sum = 0;
55
+ for (let i = 0; i < 8; i++) sum += (digits.charCodeAt(i) - 48) * (9 - i);
56
+ const check = 11 - (sum % 11);
57
+ const expected = check >= 10 ? 0 : check;
58
+ return expected === digits.charCodeAt(8) - 48;
59
+ }
60
+
61
+ const PLACEHOLDER_PREFIX = /^(?:\$|\{|<|%|\[|\(|process\.env|os\.getenv|env\[|getenv|config\.|settings\.|this\.|self\.|args\.|params\.|req\.|request\.|\.\.\.)/i;
62
+ const PLACEHOLDER_WORDS = /^(?:\*+|x{3,}|null|undefined|none|true|false|string|required|optional|redacted|changeme|change_me|your[-_ ].*|example.*|placeholder.*|dummy.*|secret|password|token|apikey|api_key)$/i;
63
+
64
+ /**
65
+ * Decide whether the value assigned to a secret-looking name is a literal
66
+ * credential or just code (identifier, call, template, placeholder).
67
+ */
68
+ export function looksLikeLiteralSecret(value) {
69
+ const v = value.replace(/^["'`]+|["'`]+$/g, '');
70
+ if (v.length < 8) return false;
71
+ if (PLACEHOLDER_PREFIX.test(v) || PLACEHOLDER_WORDS.test(v)) return false;
72
+ if (v.includes('REDACTED') || v.includes('***')) return false;
73
+ if (/[()]/.test(v)) return false; // function call / expression
74
+ if (/^[A-Za-z_][A-Za-z0-9_.]*$/.test(v) && !/\d/.test(v)) {
75
+ // plain identifier or dotted path (getPassword, config.password): code, not a secret
76
+ return false;
77
+ }
78
+ if (/^[a-z]+(?:[-_][a-z]+)+$/.test(v)) return false; // kebab/snake names (secret ids, flags), not values
79
+ const hasDigit = /\d/.test(v);
80
+ const hasSymbol = /[!@#$%^&*+/=~\-]/.test(v);
81
+ if (hasDigit || hasSymbol) return true;
82
+ return v.length >= 16 && shannonEntropy(v) >= 3.5;
83
+ }
84
+
85
+ /** High-entropy blob heuristic (opaque keys); excludes hashes, UUIDs and paths. */
86
+ export function looksLikeOpaqueKey(token) {
87
+ if (token.length < 40) return false;
88
+ if (/^sha\d+-/i.test(token)) return false; // npm/SRI integrity hashes
89
+ if (/^[0-9a-f]+$/i.test(token)) return false; // hex digests / git SHAs
90
+ if (/^[0-9a-f]{8}-[0-9a-f]{4}-/i.test(token)) return false; // UUID
91
+ if (token.startsWith('/') || token.includes('//')) return false; // path / URL remnants
92
+ // Standard base64 never has - or _, URL-safe never has /: a mix means a path or URL fragment.
93
+ if (token.includes('/') && /[-_]/.test(token)) return false;
94
+ if (!/[a-z]/.test(token) || !/[A-Z]/.test(token) || !/\d/.test(token)) return false;
95
+ return shannonEntropy(token) >= 4.5;
96
+ }
97
+
98
+ const NON_MAIL_TLDS = new Set(['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp', 'ico', 'css', 'js', 'ts', 'json', 'map', 'woff', 'woff2', 'ttf', 'eot', 'html', 'md']);
99
+ const DOC_DOMAINS = /(?:^|\.)(?:example\.(?:com|org|net)|test|invalid|localhost|local)$/i;
100
+
101
+ /** E-mail: reject asset names (logo@2x.png) and reserved documentation domains. */
102
+ export function realEmail(addr) {
103
+ const at = addr.lastIndexOf('@');
104
+ const domain = addr.slice(at + 1);
105
+ const tld = domain.slice(domain.lastIndexOf('.') + 1).toLowerCase();
106
+ if (NON_MAIL_TLDS.has(tld)) return false;
107
+ if (DOC_DOMAINS.test(domain)) return false;
108
+ return true;
109
+ }
110
+
111
+ /** International phone: leading +, 9 to 15 digits overall. */
112
+ export function plausiblePhone(raw) {
113
+ const digits = raw.replace(/\D/g, '');
114
+ return digits.length >= 9 && digits.length <= 15;
115
+ }
116
+
117
+ /** Card number candidates: Luhn + plausible leading digit, separators ignored. */
118
+ export function plausibleCard(raw) {
119
+ const digits = raw.replace(/[ -]/g, '');
120
+ if (!/^[2-6]/.test(digits)) return false;
121
+ if (/^(\d)\1+$/.test(digits)) return false;
122
+ return luhnValid(digits);
123
+ }
package/src/exec-utils.js CHANGED
@@ -156,10 +156,27 @@ export async function compileAndTest({ language, buildTool, cwd, skipTests = fal
156
156
  }
157
157
  }
158
158
 
159
- // -e flag shows full error stack traces from Maven
159
+ // Speed flags — these stack:
160
+ // -q quiet output (only ERROR-level)
161
+ // --no-snapshot-updates skip "checking for updates" of
162
+ // SNAPSHOT deps that we already have
163
+ // in ~/.m2 (saves seconds per run)
164
+ // -T 1C one thread per CPU core (no-op on
165
+ // single-module poms but harmless)
166
+ // -Dmaven.compiler.useIncremental
167
+ // Compilation=true
168
+ // default since Maven 3.9 — set
169
+ // explicitly for older runners
170
+ // -e show full stack on compile errors
171
+ const speedFlags = [
172
+ "-q",
173
+ "--no-snapshot-updates",
174
+ "-T", "1C",
175
+ "-Dmaven.compiler.useIncrementalCompilation=true"
176
+ ];
160
177
  const args = skipTests
161
- ? ["compile", "-DskipTests", "-e", ...javaCompatFlags]
162
- : ["test", "-e", ...javaCompatFlags];
178
+ ? ["compile", "-DskipTests", "-e", ...speedFlags, ...javaCompatFlags]
179
+ : ["test", "-e", ...speedFlags, ...javaCompatFlags];
163
180
 
164
181
  console.log(`[BUILD] [COMPILE] Running: ${mvnCmd} ${args.join(" ")}`);
165
182
  result = await run(mvnCmd, args, cwd, 10 * 60 * 1000, mavenEnv);
@@ -257,7 +274,12 @@ export async function compileAndTest({ language, buildTool, cwd, skipTests = fal
257
274
  else if (language === "swift" || language === "ios") {
258
275
  // SPM projects: try `swift build` if the Swift toolchain is available.
259
276
  // Xcode projects (xcodebuild) need macOS — not available on Linux Cloud Run.
260
- if (buildTool === "spm" || buildTool === "swift") {
277
+ // Accept all three SPM marker values: "spm" (legacy), "swift" (generic),
278
+ // "swiftpm" (current detector output from detectors.js for Package.swift).
279
+ // Pre-Phase-11 bug: detectProject emits "swiftpm" but this branch only
280
+ // matched "spm"/"swift", so SwiftPM projects fell through to the Xcode
281
+ // branch (swiftc -typecheck) instead of using swift build.
282
+ if (buildTool === "spm" || buildTool === "swift" || buildTool === "swiftpm") {
261
283
  console.log(`[BUILD] [COMPILE] Attempting: swift build`);
262
284
  const swiftCheck = await run("which", ["swift"], cwd, 3000);
263
285
  if (swiftCheck.code === 0) {