@open-mercato/cli 0.6.7-develop.6863.1.61001cf9a8 → 0.6.7
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/.turbo/turbo-build.log +4 -4
- package/build.mjs +7 -24
- package/dist/agentic/claude-code/hooks/entity-migration-check.ts +88 -32
- package/dist/agentic/codex/enforcement-rules.md +16 -2
- package/dist/agentic/cursor/hooks/entity-migration-check.mjs +50 -19
- package/dist/agentic/cursor/rules/entity-guard.mdc +21 -9
- package/dist/agentic/cursor/rules/generated-guard.mdc +5 -3
- package/dist/agentic/cursor/rules/open-mercato.mdc +29 -3
- package/dist/agentic/guides/cache.md +45 -0
- package/dist/agentic/guides/core.md +453 -0
- package/dist/agentic/guides/events.md +117 -0
- package/dist/agentic/guides/module-facts.json +3833 -115419
- package/dist/agentic/guides/module-system.md +127 -12
- package/dist/agentic/guides/modules/ai_assistant.md +28 -227
- package/dist/agentic/guides/modules/api_docs.md +2 -58
- package/dist/agentic/guides/modules/api_keys.md +7 -92
- package/dist/agentic/guides/modules/attachments.md +14 -119
- package/dist/agentic/guides/modules/audit_logs.md +10 -131
- package/dist/agentic/guides/modules/auth.md +33 -276
- package/dist/agentic/guides/modules/business_rules.md +14 -149
- package/dist/agentic/guides/modules/catalog.md +43 -475
- package/dist/agentic/guides/modules/channel_gmail.md +3 -82
- package/dist/agentic/guides/modules/channel_imap.md +3 -82
- package/dist/agentic/guides/modules/checkout.md +27 -299
- package/dist/agentic/guides/modules/communication_channels.md +33 -315
- package/dist/agentic/guides/modules/configs.md +8 -104
- package/dist/agentic/guides/modules/content.md +2 -57
- package/dist/agentic/guides/modules/currencies.md +17 -152
- package/dist/agentic/guides/modules/customer_accounts.md +45 -387
- package/dist/agentic/guides/modules/customers.md +85 -746
- package/dist/agentic/guides/modules/dashboards.md +10 -155
- package/dist/agentic/guides/modules/data_sync.md +16 -149
- package/dist/agentic/guides/modules/dictionaries.md +12 -107
- package/dist/agentic/guides/modules/directory.md +15 -148
- package/dist/agentic/guides/modules/entities.md +13 -145
- package/dist/agentic/guides/modules/events.md +2 -59
- package/dist/agentic/guides/modules/feature_toggles.md +9 -119
- package/dist/agentic/guides/modules/gateway_stripe.md +4 -92
- package/dist/agentic/guides/modules/generators.md +2 -45
- package/dist/agentic/guides/modules/inbox_ops.md +27 -207
- package/dist/agentic/guides/modules/integrations.md +16 -146
- package/dist/agentic/guides/modules/messages.md +24 -223
- package/dist/agentic/guides/modules/notifications.md +8 -96
- package/dist/agentic/guides/modules/onboarding.md +6 -77
- package/dist/agentic/guides/modules/payment_gateways.md +21 -164
- package/dist/agentic/guides/modules/perspectives.md +7 -77
- package/dist/agentic/guides/modules/planner.md +18 -136
- package/dist/agentic/guides/modules/portal.md +2 -93
- package/dist/agentic/guides/modules/progress.md +14 -104
- package/dist/agentic/guides/modules/query_index.md +15 -154
- package/dist/agentic/guides/modules/record_locks.md +21 -206
- package/dist/agentic/guides/modules/resources.md +30 -197
- package/dist/agentic/guides/modules/sales.md +84 -678
- package/dist/agentic/guides/modules/scheduler.md +14 -133
- package/dist/agentic/guides/modules/search.md +6 -170
- package/dist/agentic/guides/modules/security.md +35 -294
- package/dist/agentic/guides/modules/shipping_carriers.md +18 -134
- package/dist/agentic/guides/modules/sso.md +26 -151
- package/dist/agentic/guides/modules/staff.md +57 -369
- package/dist/agentic/guides/modules/storage_s3.md +5 -95
- package/dist/agentic/guides/modules/sync_akeneo.md +3 -85
- package/dist/agentic/guides/modules/sync_excel.md +6 -75
- package/dist/agentic/guides/modules/system_status_overlays.md +2 -60
- package/dist/agentic/guides/modules/translations.md +10 -104
- package/dist/agentic/guides/modules/webhooks.md +24 -203
- package/dist/agentic/guides/modules/wms.md +46 -441
- package/dist/agentic/guides/modules/workflows.md +43 -302
- package/dist/agentic/guides/queue.md +53 -0
- package/dist/agentic/guides/search.md +115 -0
- package/dist/agentic/guides/shared.md +108 -0
- package/dist/agentic/guides/ui.md +347 -0
- package/dist/agentic/shared/AGENTS.md.template +311 -124
- package/dist/agentic/shared/ai/agentic.config.json +0 -2
- package/dist/agentic/shared/ai/lessons.md +3 -26
- package/dist/agentic/shared/ai/skills/om-auto-continue-pr-loop/SKILL.md +27 -0
- package/dist/agentic/shared/ai/skills/om-auto-create-pr-loop/SKILL.md +27 -0
- package/dist/agentic/shared/ai/skills/om-auto-review-pr/SKILL.md +0 -4
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/SKILL.md +241 -20
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/ui-components.md +260 -0
- package/dist/agentic/shared/ai/skills/om-data-model-design/SKILL.md +601 -16
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/mikro-orm-cheatsheet.md +146 -0
- package/dist/agentic/shared/ai/skills/om-eject-and-customize/SKILL.md +310 -14
- package/dist/agentic/shared/ai/skills/om-help/SKILL.md +97 -15
- package/dist/agentic/shared/ai/skills/om-help/references/skills-catalog.md +84 -0
- package/dist/agentic/shared/ai/skills/om-help/references/workflow-sequences.md +193 -0
- package/dist/agentic/shared/ai/skills/om-implement-spec/SKILL.md +152 -33
- package/dist/agentic/shared/ai/skills/om-integration-builder/SKILL.md +708 -24
- package/dist/agentic/shared/ai/skills/om-integration-builder/STANDALONE.md +34 -0
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/adapter-contracts.md +762 -0
- package/dist/agentic/shared/ai/skills/om-module-scaffold/SKILL.md +820 -20
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/naming-conventions.md +50 -0
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/navigation-patterns.md +97 -0
- package/dist/agentic/shared/ai/skills/om-system-extension/SKILL.md +843 -19
- package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-contracts.md +271 -0
- package/dist/agentic/shared/ai/skills/om-trim-unused-modules/SKILL.md +63 -15
- package/dist/agentic/shared/ai/skills/om-troubleshooter/SKILL.md +467 -16
- package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnostic-commands.md +101 -0
- package/dist/agentic/shared/ai/skills/tiers.json +21 -143
- package/dist/agentic/shared/ai/skills/tiers.schema.json +40 -52
- package/dist/agentic/shared/ai/specs/README.md +3 -4
- package/dist/agentic/shared/ai/specs/SPEC-000-template.md +10 -226
- package/dist/agentic/shared/ai/trackers/github.md +4 -108
- package/dist/agentic/shared/scripts/install-skills.sh +694 -4
- package/dist/bin.js +1 -13
- package/dist/bin.js.map +2 -2
- package/dist/lib/__integration__/TC-INT-008.spec.js +8 -88
- package/dist/lib/__integration__/TC-INT-008.spec.js.map +2 -2
- package/dist/lib/agentic-init.js +3 -13
- package/dist/lib/agentic-init.js.map +2 -2
- package/dist/lib/agentic-setup.js +186 -418
- package/dist/lib/agentic-setup.js.map +2 -2
- package/dist/lib/generators/extensions/injection-widgets.js +0 -20
- package/dist/lib/generators/extensions/injection-widgets.js.map +2 -2
- package/dist/lib/generators/module-facts-discovery.js +7 -41
- package/dist/lib/generators/module-facts-discovery.js.map +2 -2
- package/dist/lib/generators/module-facts.js +45 -1387
- package/dist/lib/generators/module-facts.js.map +3 -3
- package/dist/lib/generators/module-registry.js +5 -11
- package/dist/lib/generators/module-registry.js.map +2 -2
- package/dist/lib/resolver.js +0 -2
- package/dist/lib/resolver.js.map +2 -2
- package/dist/lib/testing/integration.js +0 -5
- package/dist/lib/testing/integration.js.map +2 -2
- package/dist/mercato.js +1 -23
- package/dist/mercato.js.map +2 -2
- package/package.json +11 -13
- package/src/bin.ts +1 -33
- package/src/lib/__integration__/TC-INT-008.spec.ts +9 -107
- package/src/lib/__tests__/agentic-init.test.ts +5 -41
- package/src/lib/agentic-init.ts +3 -15
- package/src/lib/agentic-setup.ts +224 -530
- package/src/lib/generators/__tests__/module-facts.bc-guard.test.ts +2 -88
- package/src/lib/generators/__tests__/module-facts.customers.fixture.test.ts +0 -1
- package/src/lib/generators/__tests__/module-facts.discovery.test.ts +10 -54
- package/src/lib/generators/__tests__/module-subset.test.ts +0 -18
- package/src/lib/generators/extensions/injection-widgets.ts +0 -51
- package/src/lib/generators/module-facts-discovery.ts +7 -58
- package/src/lib/generators/module-facts.ts +46 -1851
- package/src/lib/generators/module-registry.ts +6 -16
- package/src/lib/resolver.ts +0 -3
- package/src/lib/testing/__tests__/integration.test.ts +0 -4
- package/src/lib/testing/integration.ts +0 -5
- package/src/mercato.ts +1 -26
- package/dist/agentic/guides/ai-workflows.md +0 -76
- package/dist/agentic/guides/architecture.md +0 -107
- package/dist/agentic/guides/backend-ui.md +0 -80
- package/dist/agentic/guides/contracts.md +0 -92
- package/dist/agentic/guides/extensions.md +0 -121
- package/dist/agentic/guides/framework-extension-points.md +0 -36
- package/dist/agentic/guides/integrations.md +0 -81
- package/dist/agentic/guides/modules/design_system.md +0 -102
- package/dist/agentic/guides/spec-delivery.md +0 -22
- package/dist/agentic/guides/testing-debugging.md +0 -80
- package/dist/agentic/guides/upstream/AGENTS.md +0 -298
- package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +0 -316
- package/dist/agentic/guides/upstream/manifest.json +0 -8
- package/dist/agentic/shared/ai/harness/README.md +0 -50
- package/dist/agentic/shared/ai/harness/RELEASE.md +0 -57
- package/dist/agentic/shared/ai/harness/cases.json +0 -13680
- package/dist/agentic/shared/ai/harness/cases.schema.json +0 -133
- package/dist/agentic/shared/ai/harness/fixtures/index.json +0 -49
- package/dist/agentic/shared/ai/harness/fixtures/seeds.json +0 -162
- package/dist/agentic/shared/ai/harness/generated-code-review-policy.md +0 -21
- package/dist/agentic/shared/ai/harness/generated-code-review-response.schema.json +0 -96
- package/dist/agentic/shared/ai/harness/generated-code-review-result.schema.json +0 -172
- package/dist/agentic/shared/ai/harness/release-matrix.json +0 -158
- package/dist/agentic/shared/ai/harness/release-result.schema.json +0 -219
- package/dist/agentic/shared/ai/harness/result.schema.json +0 -76
- package/dist/agentic/shared/ai/harness/routing-response.schema.json +0 -12
- package/dist/agentic/shared/ai/harness/target-validation-result.schema.json +0 -73
- package/dist/agentic/shared/ai/harness/validators.json +0 -78
- package/dist/agentic/shared/ai/harness/writable-ast-oracles.mjs +0 -2121
- package/dist/agentic/shared/ai/harness/writable-behavior-oracles.mjs +0 -1096
- package/dist/agentic/shared/ai/lessons/_template.md +0 -16
- package/dist/agentic/shared/ai/review-checklist.md +0 -36
- package/dist/agentic/shared/ai/skills/om-auto-implement-spec/SKILL.md +0 -21
- package/dist/agentic/shared/ai/skills/om-auto-upgrade-0.6.6-to-0.6.7/SKILL.md +0 -98
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/crud-surfaces.md +0 -16
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/frontend-and-design-system.md +0 -53
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/page-and-navigation.md +0 -13
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/quality-states.md +0 -11
- package/dist/agentic/shared/ai/skills/om-build-workflow/SKILL.md +0 -30
- package/dist/agentic/shared/ai/skills/om-build-workflow/references/activity-contracts.md +0 -12
- package/dist/agentic/shared/ai/skills/om-build-workflow/references/durability-and-progress.md +0 -13
- package/dist/agentic/shared/ai/skills/om-build-workflow/references/workflow-design.md +0 -14
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/SKILL.md +0 -28
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/attachments-and-overrides.md +0 -12
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/module-agents-and-tools.md +0 -22
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/orchestrator-agents.md +0 -12
- package/dist/agentic/shared/ai/skills/om-create-ai-agent/references/surface-selector.md +0 -19
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/integrity-and-concurrency.md +0 -19
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/migration-workflow.md +0 -13
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/schema-design.md +0 -14
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/sensitive-data.md +0 -10
- package/dist/agentic/shared/ai/skills/om-eject-and-customize/references/decision-and-procedure.md +0 -17
- package/dist/agentic/shared/ai/skills/om-evolve-harness/SKILL.md +0 -29
- package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-template.md +0 -100
- package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-workflow.md +0 -16
- package/dist/agentic/shared/ai/skills/om-evolve-harness/references/owner-selection.md +0 -17
- package/dist/agentic/shared/ai/skills/om-framework-context/SKILL.md +0 -25
- package/dist/agentic/shared/ai/skills/om-framework-context/references/resolver-procedure.md +0 -11
- package/dist/agentic/shared/ai/skills/om-framework-context/references/skew-and-escalation.md +0 -13
- package/dist/agentic/shared/ai/skills/om-help/references/delivery-workflows.md +0 -18
- package/dist/agentic/shared/ai/skills/om-help/references/task-families.md +0 -20
- package/dist/agentic/shared/ai/skills/om-implement-spec/references/phases-and-gates.md +0 -33
- package/dist/agentic/shared/ai/skills/om-implement-spec/references/planning-and-progress.md +0 -40
- package/dist/agentic/shared/ai/skills/om-implement-spec/references/report-templates.md +0 -27
- package/dist/agentic/shared/ai/skills/om-implement-spec/references/spec-resolution.md +0 -24
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/package-and-activation.md +0 -16
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/provider-families.md +0 -14
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/security-and-reliability.md +0 -15
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/sync-and-files.md +0 -12
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/SKILL.md +0 -34
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/agents/openai.yaml +0 -4
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/agentic-setup.md +0 -11
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/input-normalization.md +0 -31
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/judge-workflow.md +0 -39
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/report-template.md +0 -43
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/rules.md +0 -11
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/api-and-domain.md +0 -19
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/business-one-shot-blueprints.md +0 -172
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/data-and-migrations.md +0 -12
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/discovery-surface-catalog.md +0 -83
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/module-surfaces.md +0 -21
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/planning.md +0 -11
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/runtime-cache-and-queues.md +0 -22
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/verification.md +0 -13
- package/dist/agentic/shared/ai/skills/om-share-this-session/SKILL.md +0 -41
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/agentic-setup.md +0 -19
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/bundle-preparation.md +0 -44
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/consent-and-review.md +0 -39
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/publication.md +0 -20
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/report-templates.md +0 -57
- package/dist/agentic/shared/ai/skills/om-share-this-session/references/rules.md +0 -11
- package/dist/agentic/shared/ai/skills/om-share-this-session/scripts/prepare-share-bundle.mjs +0 -486
- package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-branches.md +0 -18
- package/dist/agentic/shared/ai/skills/om-system-extension/references/mechanism-selector.md +0 -27
- package/dist/agentic/shared/ai/skills/om-system-extension/references/read-write-roundtrip.md +0 -13
- package/dist/agentic/shared/ai/skills/om-system-extension/references/unified-overrides.md +0 -41
- package/dist/agentic/shared/ai/skills/om-system-extension/references/verification.md +0 -11
- package/dist/agentic/shared/ai/skills/om-trim-unused-modules/references/dependency-and-redirect.md +0 -15
- package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnosis-map.md +0 -16
- package/dist/agentic/shared/ai/skills/om-troubleshooter/references/regression-oracles.md +0 -14
- package/dist/agentic/shared/scripts/agent-harness-tool-server.mjs +0 -187
- package/dist/agentic/shared/scripts/check-lessons.mjs +0 -178
- package/dist/agentic/shared/scripts/evaluate-agent-harness.mjs +0 -2958
- package/dist/agentic/shared/scripts/execution-sandbox.mjs +0 -329
- package/dist/agentic/shared/scripts/framework-context.mjs +0 -888
- package/dist/agentic/shared/scripts/install-skills.mjs +0 -1029
- package/dist/agentic/shared/scripts/prepare-agent-harness-fixture.mjs +0 -222
- package/dist/agentic/shared/scripts/run-agent-harness-release.mjs +0 -1774
- package/dist/lib/generators/module-extension-facts.js +0 -1840
- package/dist/lib/generators/module-extension-facts.js.map +0 -7
- package/dist/lib/generators/module-fact-sources.js +0 -70
- package/dist/lib/generators/module-fact-sources.js.map +0 -7
- package/dist/lib/generators/module-override-targets.js +0 -688
- package/dist/lib/generators/module-override-targets.js.map +0 -7
- package/dist/lib/load-env.js +0 -24
- package/dist/lib/load-env.js.map +0 -7
- package/dist/lib/telemetry-init.js +0 -358
- package/dist/lib/telemetry-init.js.map +0 -7
- package/src/lib/__tests__/agentic-setup.ownership.test.ts +0 -386
- package/src/lib/__tests__/injection-widget-id-validation.test.ts +0 -184
- package/src/lib/__tests__/load-env.test.ts +0 -65
- package/src/lib/__tests__/telemetry-init.test.ts +0 -298
- package/src/lib/generators/__tests__/activation-adapter-coverage.test.ts +0 -92
- package/src/lib/generators/__tests__/module-extension-activations.test.ts +0 -762
- package/src/lib/generators/__tests__/module-extension-facts.test.ts +0 -404
- package/src/lib/generators/__tests__/module-facts.extension-hosts.test.ts +0 -108
- package/src/lib/generators/__tests__/module-facts.owned-contracts.test.ts +0 -561
- package/src/lib/generators/__tests__/module-facts.source-links.test.ts +0 -119
- package/src/lib/generators/__tests__/module-override-targets.roundtrip.test.ts +0 -149
- package/src/lib/generators/__tests__/module-override-targets.test.ts +0 -304
- package/src/lib/generators/module-extension-facts.ts +0 -2365
- package/src/lib/generators/module-fact-sources.ts +0 -108
- package/src/lib/generators/module-override-targets.ts +0 -863
- package/src/lib/load-env.ts +0 -30
- package/src/lib/telemetry-init.ts +0 -461
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from 'node:child_process'
|
|
2
|
-
import crypto from 'node:crypto'
|
|
3
|
-
import fs from 'node:fs'
|
|
4
|
-
import os from 'node:os'
|
|
5
|
-
import path from 'node:path'
|
|
6
|
-
import process from 'node:process'
|
|
7
|
-
|
|
8
|
-
function pathEntries(env = process.env) {
|
|
9
|
-
return String(env.PATH ?? '').split(path.delimiter).filter(Boolean)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function executableCandidate(command, env = process.env) {
|
|
13
|
-
if (path.isAbsolute(command)) return command
|
|
14
|
-
for (const directory of pathEntries(env)) {
|
|
15
|
-
const candidate = path.join(directory, command)
|
|
16
|
-
try {
|
|
17
|
-
const stat = fs.statSync(candidate)
|
|
18
|
-
if (stat.isFile()) return candidate
|
|
19
|
-
} catch { /* keep looking */ }
|
|
20
|
-
}
|
|
21
|
-
throw new Error(`sandbox executable is unavailable: ${command}`)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function resolveExecutable(command, env = process.env) {
|
|
25
|
-
return fs.realpathSync(executableCandidate(command, env))
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function trustedBubblewrapExecutable(env = process.env) {
|
|
29
|
-
const executable = resolveExecutable('bwrap', env)
|
|
30
|
-
const stat = fs.lstatSync(executable)
|
|
31
|
-
if (!stat.isFile() || stat.isSymbolicLink() || stat.uid !== 0 || (stat.mode & 0o022) !== 0) {
|
|
32
|
-
throw new Error('Linux target isolation requires a root-owned, non-group/world-writable Bubblewrap executable')
|
|
33
|
-
}
|
|
34
|
-
return executable
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function regularDirectory(root, label) {
|
|
38
|
-
if (!path.isAbsolute(root)) throw new Error(`${label} must be absolute`)
|
|
39
|
-
const stat = fs.lstatSync(root)
|
|
40
|
-
if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error(`${label} must be a regular directory`)
|
|
41
|
-
return fs.realpathSync(root)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// True when `parent` is `candidate` or one of its ancestors.
|
|
45
|
-
function containsPath(parent, candidate) {
|
|
46
|
-
const relative = path.relative(parent, candidate)
|
|
47
|
-
return relative === '' || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative))
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function uniqueExistingDirectories(values) {
|
|
51
|
-
return [...new Set(values)].filter((entry) => {
|
|
52
|
-
try { return fs.statSync(entry).isDirectory() } catch { return false }
|
|
53
|
-
}).map((entry) => fs.realpathSync(entry))
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function collapseReadOnlyRoots(values) {
|
|
57
|
-
const roots = [...new Set(uniqueExistingDirectories(values))]
|
|
58
|
-
.sort((left, right) => left.split(path.sep).length - right.split(path.sep).length || left.localeCompare(right))
|
|
59
|
-
const result = []
|
|
60
|
-
for (const root of roots) {
|
|
61
|
-
const nested = result.some((parent) => {
|
|
62
|
-
const relative = path.relative(parent, root)
|
|
63
|
-
return relative === '' || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative))
|
|
64
|
-
})
|
|
65
|
-
if (!nested) result.push(root)
|
|
66
|
-
}
|
|
67
|
-
return result
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function linuxMergedUsrSymlinkArgs() {
|
|
71
|
-
const aliases = [
|
|
72
|
-
['/bin', 'usr/bin'],
|
|
73
|
-
['/sbin', 'usr/sbin'],
|
|
74
|
-
['/lib', 'usr/lib'],
|
|
75
|
-
['/lib64', 'usr/lib64'],
|
|
76
|
-
]
|
|
77
|
-
return aliases.flatMap(([alias, expected]) => {
|
|
78
|
-
try {
|
|
79
|
-
const stat = fs.lstatSync(alias)
|
|
80
|
-
return stat.isSymbolicLink() && fs.readlinkSync(alias) === expected
|
|
81
|
-
? ['--symlink', expected, alias]
|
|
82
|
-
: []
|
|
83
|
-
} catch { return [] }
|
|
84
|
-
})
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function uniqueExistingRegularFiles(values) {
|
|
88
|
-
return [...new Set(values)].filter((entry) => {
|
|
89
|
-
try { return fs.statSync(entry).isFile() } catch { return false }
|
|
90
|
-
})
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function runtimeReadRoots(command, env) {
|
|
94
|
-
const executablePath = executableCandidate(command, env)
|
|
95
|
-
const executable = fs.realpathSync(executablePath)
|
|
96
|
-
const nodeInstallRoot = path.dirname(path.dirname(fs.realpathSync(process.execPath)))
|
|
97
|
-
const nodeLauncher = (() => {
|
|
98
|
-
try {
|
|
99
|
-
const candidate = executableCandidate(process.platform === 'win32' ? 'node.exe' : 'node', env)
|
|
100
|
-
if (fs.realpathSync(candidate) === fs.realpathSync(process.execPath)) return path.dirname(candidate)
|
|
101
|
-
if (process.platform !== 'win32') {
|
|
102
|
-
const launcher = fs.lstatSync(candidate)
|
|
103
|
-
const launcherRoot = path.dirname(candidate)
|
|
104
|
-
const root = fs.lstatSync(launcherRoot)
|
|
105
|
-
const realTemporary = fs.realpathSync(os.tmpdir())
|
|
106
|
-
const realLauncherRoot = fs.realpathSync(launcherRoot)
|
|
107
|
-
const relative = path.relative(realTemporary, realLauncherRoot)
|
|
108
|
-
const insideTemporary = relative !== '' && !relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative)
|
|
109
|
-
const exactWrapper = `#!/bin/sh\nexec ${JSON.stringify(fs.realpathSync(process.execPath))} "$@"\n`
|
|
110
|
-
if (insideTemporary && /^xfs-[a-f0-9]+$/.test(path.basename(realLauncherRoot))
|
|
111
|
-
&& root.isDirectory() && !root.isSymbolicLink()
|
|
112
|
-
&& launcher.isFile() && !launcher.isSymbolicLink() && launcher.size <= 256 && (launcher.mode & 0o111) !== 0
|
|
113
|
-
&& fs.readFileSync(candidate, 'utf8') === exactWrapper) return realLauncherRoot
|
|
114
|
-
}
|
|
115
|
-
return undefined
|
|
116
|
-
} catch { return undefined }
|
|
117
|
-
})()
|
|
118
|
-
const system = process.platform === 'darwin'
|
|
119
|
-
? ['/System', '/usr', '/bin', '/sbin', '/Library/Apple', '/Library/Fonts', '/Library/ColorSync', '/Library/Keyboard Layouts', '/Library/Keychains', '/Library/Security/Trust Settings', '/private/var/db', '/private/etc/ssl', '/etc/ssl', '/dev']
|
|
120
|
-
: ['/usr', '/bin', '/sbin', '/lib', '/lib64', '/etc/ssl', '/etc/ca-certificates']
|
|
121
|
-
return collapseReadOnlyRoots([
|
|
122
|
-
...system,
|
|
123
|
-
nodeInstallRoot,
|
|
124
|
-
path.dirname(executablePath),
|
|
125
|
-
path.dirname(executable),
|
|
126
|
-
...(nodeLauncher ? [nodeLauncher] : []),
|
|
127
|
-
])
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function sandboxLiteral(value) {
|
|
131
|
-
return String(value).replaceAll('\\', '\\\\').replaceAll('"', '\\"')
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export function assertSandboxNetworkModeSupported(networkMode, platform = process.platform) {
|
|
135
|
-
if (!['none', 'loopback', 'all'].includes(networkMode)) {
|
|
136
|
-
throw new Error(`invalid sandbox network mode: ${String(networkMode)}`)
|
|
137
|
-
}
|
|
138
|
-
if (platform === 'darwin' && networkMode === 'loopback') {
|
|
139
|
-
throw new Error('isolated loopback is unavailable with macOS sandbox-exec; run this lane in a Linux VM/container with Bubblewrap')
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export function assertSandboxRuntimeAvailable(networkMode, platform = process.platform, env = process.env) {
|
|
144
|
-
assertSandboxNetworkModeSupported(networkMode, platform)
|
|
145
|
-
if (platform === 'darwin') {
|
|
146
|
-
if (!fs.existsSync('/usr/bin/sandbox-exec')) throw new Error('macOS target isolation requires /usr/bin/sandbox-exec')
|
|
147
|
-
return '/usr/bin/sandbox-exec'
|
|
148
|
-
}
|
|
149
|
-
if (platform === 'linux') {
|
|
150
|
-
return trustedBubblewrapExecutable(env)
|
|
151
|
-
}
|
|
152
|
-
throw new Error(`target isolation is unsupported on ${platform}; use a Linux VM/container with Bubblewrap`)
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export function verifyLinuxSandboxIsolation(env = process.env) {
|
|
156
|
-
const bubblewrap = trustedBubblewrapExecutable(env)
|
|
157
|
-
const probeRoot = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'om-bwrap-probe-')))
|
|
158
|
-
const nonce = crypto.randomBytes(18).toString('hex')
|
|
159
|
-
const marker = `OM_BWRAP_ISOLATED_${nonce}`
|
|
160
|
-
const node = fs.realpathSync(process.execPath)
|
|
161
|
-
const baseArgs = [
|
|
162
|
-
'--die-with-parent',
|
|
163
|
-
'--new-session',
|
|
164
|
-
...linuxIsolationArgs('loopback'),
|
|
165
|
-
...linuxMergedUsrSymlinkArgs(),
|
|
166
|
-
'--proc', '/proc',
|
|
167
|
-
'--dev', '/dev',
|
|
168
|
-
'--tmpfs', '/tmp',
|
|
169
|
-
'--bind', probeRoot, probeRoot,
|
|
170
|
-
]
|
|
171
|
-
for (const root of runtimeReadRoots(node, env)) baseArgs.push('--ro-bind', root, root)
|
|
172
|
-
baseArgs.push('--chdir', probeRoot, '--', node, '-e')
|
|
173
|
-
const outerProbe = `
|
|
174
|
-
const { spawnSync } = require('node:child_process')
|
|
175
|
-
const net = require('node:net')
|
|
176
|
-
const bubblewrap = process.argv[1]
|
|
177
|
-
const args = JSON.parse(process.argv[2])
|
|
178
|
-
const marker = process.argv[3]
|
|
179
|
-
const host = net.createServer()
|
|
180
|
-
host.once('error', () => process.exit(71))
|
|
181
|
-
host.listen(0, '127.0.0.1', () => {
|
|
182
|
-
const address = host.address()
|
|
183
|
-
if (!address || typeof address === 'string') process.exit(72)
|
|
184
|
-
const inner = \`
|
|
185
|
-
const net = require('node:net')
|
|
186
|
-
const fs = require('node:fs')
|
|
187
|
-
const marker = \${JSON.stringify(marker)}
|
|
188
|
-
const hostPort = \${address.port}
|
|
189
|
-
const local = net.createServer((socket) => socket.end())
|
|
190
|
-
const fail = () => process.exit(81)
|
|
191
|
-
const capabilities = fs.readFileSync('/proc/self/status', 'utf8')
|
|
192
|
-
.split('\\\\n')
|
|
193
|
-
.filter((line) => /^Cap(?:Inh|Prm|Eff|Bnd|Amb):/.test(line))
|
|
194
|
-
.map((line) => line.split(/:\\\\s+/)[1])
|
|
195
|
-
if (capabilities.length !== 5 || capabilities.some((value) => !/^0+$/.test(value))) fail()
|
|
196
|
-
local.once('error', fail)
|
|
197
|
-
local.listen(0, '127.0.0.1', () => {
|
|
198
|
-
const address = local.address()
|
|
199
|
-
if (!address || typeof address === 'string') fail()
|
|
200
|
-
const self = net.connect(address.port, '127.0.0.1')
|
|
201
|
-
self.once('error', fail)
|
|
202
|
-
self.once('connect', () => {
|
|
203
|
-
self.destroy()
|
|
204
|
-
local.close()
|
|
205
|
-
const outside = net.connect(hostPort, '127.0.0.1')
|
|
206
|
-
outside.once('connect', () => process.exit(82))
|
|
207
|
-
outside.once('error', () => { console.log(marker); process.exit(0) })
|
|
208
|
-
outside.setTimeout(1500, () => { outside.destroy(); console.log(marker); process.exit(0) })
|
|
209
|
-
})
|
|
210
|
-
})
|
|
211
|
-
setTimeout(fail, 4000).unref()
|
|
212
|
-
\`
|
|
213
|
-
const result = spawnSync(bubblewrap, [...args, inner], { encoding: 'utf8', timeout: 7000 })
|
|
214
|
-
const passed = result.status === 0 && result.stdout.trim() === marker
|
|
215
|
-
host.close(() => process.exit(passed ? 0 : 73))
|
|
216
|
-
})
|
|
217
|
-
setTimeout(() => process.exit(74), 9000).unref()
|
|
218
|
-
`
|
|
219
|
-
try {
|
|
220
|
-
const result = spawnSync(node, ['-e', outerProbe, bubblewrap, JSON.stringify(baseArgs), marker], {
|
|
221
|
-
cwd: probeRoot,
|
|
222
|
-
env: { PATH: String(env.PATH ?? ''), TZ: 'UTC' },
|
|
223
|
-
encoding: 'utf8',
|
|
224
|
-
timeout: 10_000,
|
|
225
|
-
})
|
|
226
|
-
if (result.status !== 0 || result.error) {
|
|
227
|
-
throw new Error('Bubblewrap isolation probe failed: private user/network namespaces, capability-free payloads, and isolated loopback are required')
|
|
228
|
-
}
|
|
229
|
-
} finally {
|
|
230
|
-
fs.rmSync(probeRoot, { recursive: true, force: true })
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
export function macSandboxProfile({ command, writableRoots, readOnlyRoots, networkMode, env }) {
|
|
235
|
-
assertSandboxNetworkModeSupported(networkMode, 'darwin')
|
|
236
|
-
const writable = writableRoots.map((root, index) => regularDirectory(root, `writable sandbox root ${index + 1}`))
|
|
237
|
-
const readOnly = readOnlyRoots.map((root, index) => regularDirectory(root, `read-only sandbox root ${index + 1}`))
|
|
238
|
-
const readable = uniqueExistingDirectories([...writable, ...readOnly, ...runtimeReadRoots(command, env)])
|
|
239
|
-
return [
|
|
240
|
-
'(version 1)',
|
|
241
|
-
'(deny default)',
|
|
242
|
-
'(import "system.sb")',
|
|
243
|
-
'(allow process*)',
|
|
244
|
-
'(allow signal)',
|
|
245
|
-
'(allow sysctl-read)',
|
|
246
|
-
'(allow file-read-metadata)',
|
|
247
|
-
'(allow mach-lookup (global-name-regex #"^org\\.chromium\\.Chromium\\.MachPortRendezvousServer\\.[0-9]+$"))',
|
|
248
|
-
'(allow mach-register (global-name-regex #"^org\\.chromium\\.Chromium\\.MachPortRendezvousServer\\.[0-9]+$"))',
|
|
249
|
-
'(allow iokit-open-user-client (iokit-user-client-class "RootDomainUserClient"))',
|
|
250
|
-
...readable.map((root) => `(allow file-read* (subpath "${sandboxLiteral(root)}"))`),
|
|
251
|
-
...writable.map((root) => `(allow file-write* (subpath "${sandboxLiteral(root)}"))`),
|
|
252
|
-
...(networkMode === 'all' ? ['(allow network*)'] : []),
|
|
253
|
-
...readOnly.map((root) => `(deny file-write* (subpath "${sandboxLiteral(root)}"))`),
|
|
254
|
-
].join(' ')
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
function macInvocation({ command, args, cwd, writableRoots, readOnlyRoots, networkMode, env }) {
|
|
258
|
-
const sandbox = '/usr/bin/sandbox-exec'
|
|
259
|
-
assertSandboxRuntimeAvailable(networkMode, 'darwin', env)
|
|
260
|
-
const profile = macSandboxProfile({ command, writableRoots, readOnlyRoots, networkMode, env })
|
|
261
|
-
return { command: sandbox, args: ['-p', profile, resolveExecutable(command, env), ...args], cwd: regularDirectory(cwd, 'sandbox cwd'), env }
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
export function linuxNamespaceArgs(networkMode) {
|
|
265
|
-
if (!['none', 'loopback', 'all'].includes(networkMode)) throw new Error(`invalid sandbox network mode: ${String(networkMode)}`)
|
|
266
|
-
return ['--unshare-all', ...(networkMode === 'all' ? ['--share-net'] : [])]
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
export function linuxIsolationArgs(networkMode) {
|
|
270
|
-
return [...linuxNamespaceArgs(networkMode), '--cap-drop', 'ALL']
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
export function linuxNetworkReadFiles(networkMode) {
|
|
274
|
-
linuxNamespaceArgs(networkMode)
|
|
275
|
-
return networkMode === 'all'
|
|
276
|
-
? ['/etc/resolv.conf', '/etc/hosts', '/etc/nsswitch.conf']
|
|
277
|
-
: []
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
function linuxInvocation({ command, args, cwd, writableRoots, readOnlyRoots, networkMode, env }) {
|
|
281
|
-
const bubblewrap = assertSandboxRuntimeAvailable(networkMode, 'linux', env)
|
|
282
|
-
const writable = writableRoots.map((root, index) => regularDirectory(root, `writable sandbox root ${index + 1}`))
|
|
283
|
-
const readOnly = readOnlyRoots.map((root, index) => regularDirectory(root, `read-only sandbox root ${index + 1}`))
|
|
284
|
-
const readable = uniqueExistingDirectories([...readOnly, ...runtimeReadRoots(command, env)])
|
|
285
|
-
const networkReadable = uniqueExistingRegularFiles(linuxNetworkReadFiles(networkMode))
|
|
286
|
-
const sandboxArgs = [
|
|
287
|
-
'--die-with-parent',
|
|
288
|
-
'--new-session',
|
|
289
|
-
...linuxIsolationArgs(networkMode),
|
|
290
|
-
...linuxMergedUsrSymlinkArgs(),
|
|
291
|
-
'--proc', '/proc',
|
|
292
|
-
'--dev', '/dev',
|
|
293
|
-
'--tmpfs', '/tmp',
|
|
294
|
-
]
|
|
295
|
-
for (const root of writable) sandboxArgs.push('--bind', root, root)
|
|
296
|
-
// Apply read-only mounts last so a nested dependency root cannot be shadowed
|
|
297
|
-
// by a later writable parent bind. Runtime roots are derived incidentally — the
|
|
298
|
-
// interpreter, the system tree, and the command's own directory — so one of them can
|
|
299
|
-
// be a writable root or its ANCESTOR, and mounting that last would re-mount the whole
|
|
300
|
-
// writable root read-only. Those are dropped: anything inside a writable bind is
|
|
301
|
-
// already reachable through it. Explicitly declared readOnlyRoots are never dropped,
|
|
302
|
-
// because a nested read-only dependency tree overriding its writable parent is exactly
|
|
303
|
-
// what this ordering exists to guarantee.
|
|
304
|
-
for (const root of readable) {
|
|
305
|
-
if (!readOnly.includes(root) && writable.some((writableRoot) => containsPath(root, writableRoot))) continue
|
|
306
|
-
sandboxArgs.push('--ro-bind', root, root)
|
|
307
|
-
}
|
|
308
|
-
for (const file of networkReadable) sandboxArgs.push('--ro-bind', file, file)
|
|
309
|
-
const realCwd = regularDirectory(cwd, 'sandbox cwd')
|
|
310
|
-
sandboxArgs.push('--chdir', realCwd, '--', resolveExecutable(command, env), ...args)
|
|
311
|
-
return { command: bubblewrap, args: sandboxArgs, cwd: realCwd, env }
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
export function sandboxedInvocation(options) {
|
|
315
|
-
const networkMode = options.networkMode ?? (options.networkAllowed === true ? 'all' : 'none')
|
|
316
|
-
assertSandboxNetworkModeSupported(networkMode)
|
|
317
|
-
const invocation = {
|
|
318
|
-
...options,
|
|
319
|
-
args: options.args ?? [],
|
|
320
|
-
writableRoots: options.writableRoots ?? [],
|
|
321
|
-
readOnlyRoots: options.readOnlyRoots ?? [],
|
|
322
|
-
networkMode,
|
|
323
|
-
env: options.env ?? {},
|
|
324
|
-
}
|
|
325
|
-
resolveExecutable(invocation.command, invocation.env)
|
|
326
|
-
if (process.platform === 'darwin') return macInvocation(invocation)
|
|
327
|
-
if (process.platform === 'linux') return linuxInvocation(invocation)
|
|
328
|
-
throw new Error(`target isolation is unsupported on ${process.platform}; use macOS sandbox-exec or Linux bubblewrap`)
|
|
329
|
-
}
|