@aifabrix/builder 2.52.1 → 2.53.1
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/lib/app/deploy-config.js +3 -2
- package/lib/channels/add-channel.js +11 -41
- package/lib/channels/approval-guides/index.js +3 -0
- package/lib/channels/approval-guides/microsoft-copilot.js +26 -17
- package/lib/channels/channel-add-existing.js +72 -0
- package/lib/channels/channel-runtime-resolver.js +5 -1
- package/lib/channels/channel-status-display.js +30 -3
- package/lib/channels/microsoft-copilot-entra-sso-form.js +73 -2
- package/lib/channels/microsoft-copilot-entra-sso.js +26 -5
- package/lib/channels/microsoft-copilot-limits.js +22 -3
- package/lib/channels/microsoft-copilot-package.js +59 -14
- package/lib/channels/microsoft-copilot-validate.js +40 -10
- package/lib/cli/attach-default-help-examples.js +102 -0
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-credential-deployment.js +7 -5
- package/lib/cli/setup-utility-validate.js +1 -0
- package/lib/commands/credential-push.js +37 -5
- package/lib/commands/package-score.js +72 -0
- package/lib/commands/role-assistant.js +46 -8
- package/lib/deployment/deployer-poll-run.js +2 -2
- package/lib/deployment/deployer.js +1 -1
- package/lib/deployment/environment.js +2 -2
- package/lib/external-system/deploy.js +11 -21
- package/lib/integration-definition/apply.js +12 -14
- package/lib/integration-definition/enrich-openapi-operations.js +9 -10
- package/lib/lab/package-parity-score.js +417 -0
- package/lib/programmatic/capability-registry.js +1 -0
- package/lib/programmatic/help-content/channel-onboarding.md +35 -0
- package/lib/programmatic/help-content/cip-overview.md +27 -0
- package/lib/programmatic/help-content/connected-system-ui.md +70 -0
- package/lib/programmatic/help-content/dimensions-guide.md +23 -0
- package/lib/programmatic/help-content/enterprise-sync-fabrix.md +123 -0
- package/lib/programmatic/help-content/overview.md +25 -0
- package/lib/programmatic/help-content/subscription-guide.md +27 -0
- package/lib/programmatic/help-content/workflow.md +50 -0
- package/lib/programmatic/openapi-component-schemas.js +1 -0
- package/lib/programmatic/openapi-descriptions.js +6 -0
- package/lib/programmatic/openapi-envelope-examples.js +11 -0
- package/lib/programmatic/openapi-operation-bindings.js +5 -0
- package/lib/programmatic/openapi-request-schemas.js +39 -13
- package/lib/programmatic/openapi-result-schemas.js +30 -0
- package/lib/programmatic/openapi-schema-descriptions-core.js +18 -0
- package/lib/programmatic/openapi-schema-descriptions-operations.js +19 -0
- package/lib/programmatic/persist-supplied-openapi.js +180 -0
- package/lib/programmatic/route-handler-map.js +6 -0
- package/lib/programmatic/run-integration-definition.js +13 -5
- package/lib/role-assistant/evidence-sync.js +55 -7
- package/lib/role-assistant/test-runner-attachments.js +118 -0
- package/lib/role-assistant/test-runner-bid-apply.js +100 -21
- package/lib/role-assistant/test-runner-bid-document.js +1 -1
- package/lib/role-assistant/test-runner-start-payload.js +96 -0
- package/lib/role-assistant/test-runner-workhub-answers.js +11 -7
- package/lib/role-assistant/test-runner-workhub-helpers.js +100 -0
- package/lib/role-assistant/test-runner-workhub-soft.js +86 -0
- package/lib/role-assistant/test-runner-workhub.js +68 -105
- package/lib/role-assistant/test-runner.js +5 -63
- package/lib/role-assistant/test-suite.js +33 -40
- package/lib/schema/external-datasource.schema.json +13 -4
- package/lib/utils/compose-generator.js +10 -1
- package/lib/utils/compose-traefik-extra-routes.js +107 -0
- package/lib/utils/docker-build.js +2 -2
- package/lib/utils/help-builder.js +2 -1
- package/lib/utils/promote-dev-docker-image.js +15 -10
- package/package.json +14 -16
- package/templates/README.md +12 -1
- package/templates/applications/dataplane/application.yaml +8 -1
- package/templates/applications/dataplane/env.template +1 -1
- package/templates/applications/miso-controller/application.yaml +2 -1
- package/templates/applications/miso-controller/rbac.yaml +1 -0
- package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +6 -2
- package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +8 -5
- package/templates/channels/microsoft-copilot/fi-fi.template.json.hbs +7 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +74 -22
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +29 -14
- package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +6 -2
- package/templates/python/docker-compose.hbs +36 -0
- package/templates/typescript/docker-compose.hbs +36 -0
- package/.cursor/plans/Archive/157.1-security-quality-violations-by-type.csv +0 -374
- package/.cursor/process/README.md +0 -9
- package/.cursor/rules/anchor-docs.mdc +0 -15
- package/.cursor/rules/assistant-driven-integration-build.mdc +0 -40
- package/.cursor/rules/cli-layout.mdc +0 -81
- package/.cursor/rules/cli-product-neutral.mdc +0 -43
- package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +0 -49
- package/.cursor/rules/docs-rules.mdc +0 -32
- package/.cursor/rules/plan-rules/application-lifecycle.mdc +0 -30
- package/.cursor/rules/plan-rules/plan-frontmatter.mdc +0 -35
- package/.cursor/rules/plan-rules/plan-lifecycle.mdc +0 -31
- package/.cursor/rules/plan-rules/plan-validation-gate.mdc +0 -34
- package/.cursor/rules/project-rules.mdc +0 -913
- package/.cursor/skills/README.md +0 -15
- package/.dockerignore +0 -52
- package/.eslintignore +0 -22
- package/.markdownlint.json +0 -14
- package/anchor-docs/README.md +0 -10
- package/anchor-docs/_TEMPLATE +0 -24
- package/babel.config.js +0 -6
- package/bin/builder-api-cleanup.js +0 -26
- package/bin/builder-api-nest.js +0 -10
- package/bin/builder-api-spike.js +0 -19
- package/enterprise-knowledge/README.md +0 -50
- package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +0 -22
- package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +0 -15
- package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +0 -69
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +0 -52
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +0 -29
- package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +0 -2
- package/integration/README.md +0 -81
- package/integration/github/README.md +0 -53
- package/integration/github/application.json +0 -21
- package/integration/github/deploy.js +0 -72
- package/integration/github/env.template +0 -11
- package/integration/github/github-datasource-issue-comments.json +0 -239
- package/integration/github/github-datasource-issues.json +0 -399
- package/integration/github/github-datasource-repository.json +0 -354
- package/integration/github/github-deploy.json +0 -1202
- package/integration/github/github-system.json +0 -82
- package/integration/hubspot-test/README.md +0 -159
- package/integration/hubspot-test/application.json +0 -54
- package/integration/hubspot-test/companies.json +0 -2048
- package/integration/hubspot-test/create-hubspot.js +0 -523
- package/integration/hubspot-test/env.template +0 -4
- package/integration/hubspot-test/hubspot-test-datasource-company.json +0 -138
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +0 -146
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +0 -146
- package/integration/hubspot-test/hubspot-test-datasource-users.json +0 -76
- package/integration/hubspot-test/hubspot-test-deploy.json +0 -2160
- package/integration/hubspot-test/hubspot-test-system.json +0 -74
- package/integration/hubspot-test/rbac.json +0 -166
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +0 -20
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +0 -9
- package/integration/hubspot-test/test-artifacts/wizard-invalid-add-datasource.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-app-name.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-create.yaml +0 -7
- package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-select.yaml +0 -7
- package/integration/hubspot-test/test-artifacts/wizard-invalid-known-platform.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-app.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
- package/integration/hubspot-test/test-artifacts/wizard-invalid-mode.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-file.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-url.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-source.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-array-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +0 -5
- package/integration/hubspot-test/test-dataplane-down-helpers.js +0 -249
- package/integration/hubspot-test/test-dataplane-down-tests.js +0 -386
- package/integration/hubspot-test/test-dataplane-down.js +0 -209
- package/integration/hubspot-test/test.js +0 -1588
- package/integration/hubspot-test/wizard-hubspot-e2e.yaml +0 -16
- package/integration/hubspot-test/wizard-hubspot-platform.yaml +0 -8
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +0 -23
- package/integration/roundtrip-test-local/README.md +0 -143
- package/integration/roundtrip-test-local/application.yaml +0 -13
- package/integration/roundtrip-test-local/env.template +0 -15
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +0 -14
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +0 -61
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +0 -25
- package/integration/roundtrip-test-local2/README.md +0 -143
- package/integration/roundtrip-test-local2/application.yaml +0 -13
- package/integration/roundtrip-test-local2/env.template +0 -15
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +0 -31
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +0 -86
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +0 -25
- package/integration/test/wizard.yaml +0 -8
- package/jest.config.coverage.js +0 -37
- package/jest.config.default.js +0 -11
- package/jest.config.integration.fixtures.js +0 -22
- package/jest.config.integration.js +0 -33
- package/jest.config.isolated.js +0 -11
- package/jest.config.manual.js +0 -30
- package/jest.global-live-fabrix-hooks.js +0 -36
- package/jest.isolated-projects.js +0 -283
- package/jest.projects.js +0 -79
- package/lib/integration-definition/openapi-enrichment/hubspot-crm-companies.json +0 -205
- package/packages/builder-api/README.md +0 -120
- package/packages/builder-api/package.json +0 -30
- package/packages/builder-api/src/app.module.ts +0 -7
- package/packages/builder-api/src/auth/auth.module.ts +0 -5
- package/packages/builder-api/src/external-system/external-system.module.ts +0 -5
- package/packages/builder-api/src/main.ts +0 -16
- package/packages/builder-api/tsconfig.json +0 -15
- package/scripts/check-builder-api-architecture-grep.js +0 -79
- package/scripts/check-datasource-test-run-schema-sync.js +0 -34
- package/scripts/ci-fix.sh +0 -19
- package/scripts/ci-simulate.sh +0 -19
- package/scripts/diagnose-cli.js +0 -150
- package/scripts/docker_image_content_gate.js +0 -47
- package/scripts/docker_image_content_gate.sh +0 -5
- package/scripts/export-builder-api-evidence.js +0 -262
- package/scripts/install-local.js +0 -490
- package/scripts/lib/builder-api-docker-staging-copy.js +0 -60
- package/scripts/lib/builder-api-docker-staging-core.js +0 -183
- package/scripts/lib/docker-image-content-gate-core.js +0 -166
- package/scripts/lib/plan-actor.js +0 -109
- package/scripts/lib/plan-config.js +0 -20
- package/scripts/lib/plan-gates.js +0 -154
- package/scripts/lib/plan-meta.js +0 -104
- package/scripts/lib/plan-parse.js +0 -162
- package/scripts/lib/plan-prevalidate-gates.js +0 -337
- package/scripts/lib/plan-run-core.js +0 -125
- package/scripts/lib/plan-run-report.js +0 -119
- package/scripts/plan-approve.js +0 -24
- package/scripts/plan-archive.js +0 -49
- package/scripts/plan-run.js +0 -13
- package/scripts/plan-set-actor.js +0 -21
- package/scripts/plan-validate.js +0 -80
- package/scripts/pnpm/af.mjs +0 -125
- package/scripts/pnpm/check-quiet.mjs +0 -32
- package/scripts/pnpm/dev-install.mjs +0 -29
- package/scripts/pnpm/dev-reload.mjs +0 -18
- package/scripts/pnpm/help.mjs +0 -55
- package/scripts/pnpm/lib/dev-reload-core.mjs +0 -189
- package/scripts/pnpm/lib/dev-reload-log-capture.mjs +0 -67
- package/scripts/pnpm/lib/dev-reload-log-utils.mjs +0 -32
- package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +0 -124
- package/scripts/pnpm/lib/resolve-app-url.mjs +0 -183
- package/scripts/pnpm/lib/spinner.mjs +0 -42
- package/scripts/pnpm-global-remove.js +0 -48
- package/scripts/stage_builder_api_for_docker.js +0 -65
- package/scripts/sync-builder-api-template.js +0 -44
- package/scripts/test-dataplane-bootstrap.js +0 -331
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime file discovery for builder-api Docker staging (plan 154.3).
|
|
3
|
-
*
|
|
4
|
-
* @fileoverview Require-graph walk + supplemental runtime assets
|
|
5
|
-
* @author AI Fabrix Team
|
|
6
|
-
* @version 1.0.0
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
'use strict';
|
|
10
|
-
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const path = require('path');
|
|
13
|
-
|
|
14
|
-
const REQUIRE_RE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
15
|
-
|
|
16
|
-
/** @type {readonly string[]} */
|
|
17
|
-
const ENTRY_FILES = ['bin/builder-api-spike.js', 'bin/builder-api-cleanup.js'];
|
|
18
|
-
|
|
19
|
-
/** @type {readonly string[]} */
|
|
20
|
-
const STAGING_SKIP_FILES = ['package.json', 'package-lock.json'];
|
|
21
|
-
|
|
22
|
-
/** @type {readonly string[]} */
|
|
23
|
-
const SUPPLEMENTAL_DIRS = [
|
|
24
|
-
'lib/schema',
|
|
25
|
-
'lib/programmatic/help-content',
|
|
26
|
-
'templates/openapi',
|
|
27
|
-
'templates/external-system',
|
|
28
|
-
'lib/datasource/capability/templates'
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
/** @type {readonly string[]} */
|
|
32
|
-
const MANIFEST_FORBIDDEN_PREFIXES = [
|
|
33
|
-
'templates/applications/',
|
|
34
|
-
'templates/github/',
|
|
35
|
-
'templates/infra/',
|
|
36
|
-
'templates/python/',
|
|
37
|
-
'templates/typescript/',
|
|
38
|
-
'templates/channels/',
|
|
39
|
-
'integration/',
|
|
40
|
-
'tests/',
|
|
41
|
-
'scripts/',
|
|
42
|
-
'.cursor/',
|
|
43
|
-
'builder/',
|
|
44
|
-
'packages/',
|
|
45
|
-
'docs/',
|
|
46
|
-
'bin/aifabrix.js',
|
|
47
|
-
'lib/cli/'
|
|
48
|
-
];
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* @param {string} repoRoot
|
|
52
|
-
* @param {string} fromFile
|
|
53
|
-
* @param {string} req
|
|
54
|
-
* @returns {string|null}
|
|
55
|
-
*/
|
|
56
|
-
function resolveRelativeRequire(repoRoot, fromFile, req) {
|
|
57
|
-
if (!req.startsWith('.')) {
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
const base = path.dirname(fromFile);
|
|
61
|
-
let resolved = path.resolve(repoRoot, base, req);
|
|
62
|
-
if (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {
|
|
63
|
-
resolved = path.join(resolved, 'index.js');
|
|
64
|
-
}
|
|
65
|
-
if (!resolved.endsWith('.js') && fs.existsSync(`${resolved}.js`)) {
|
|
66
|
-
resolved = `${resolved}.js`;
|
|
67
|
-
}
|
|
68
|
-
if (!fs.existsSync(resolved)) {
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
return path.relative(repoRoot, resolved).split(path.sep).join('/');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* @param {string} repoRoot
|
|
76
|
-
* @param {string} relFile
|
|
77
|
-
* @returns {string[]}
|
|
78
|
-
*/
|
|
79
|
-
function collectRequiresFromFile(repoRoot, relFile) {
|
|
80
|
-
const abs = path.join(repoRoot, relFile);
|
|
81
|
-
const content = fs.readFileSync(abs, 'utf8');
|
|
82
|
-
const found = [];
|
|
83
|
-
let match;
|
|
84
|
-
while ((match = REQUIRE_RE.exec(content)) !== null) {
|
|
85
|
-
const target = resolveRelativeRequire(repoRoot, relFile, match[1]);
|
|
86
|
-
if (target) {
|
|
87
|
-
found.push(target);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return found;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* @param {string} dir
|
|
95
|
-
* @param {string} repoRoot
|
|
96
|
-
* @param {Set<string>} out
|
|
97
|
-
* @returns {void}
|
|
98
|
-
*/
|
|
99
|
-
function addDirectoryFiles(dir, repoRoot, out) {
|
|
100
|
-
const abs = path.join(repoRoot, dir);
|
|
101
|
-
if (!fs.existsSync(abs)) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
for (const entry of fs.readdirSync(abs, { withFileTypes: true })) {
|
|
105
|
-
const rel = path.join(dir, entry.name).split(path.sep).join('/');
|
|
106
|
-
if (entry.isDirectory()) {
|
|
107
|
-
addDirectoryFiles(rel, repoRoot, out);
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
out.add(rel);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* @param {string} repoRoot
|
|
116
|
-
* @returns {string[]}
|
|
117
|
-
*/
|
|
118
|
-
function discoverRuntimeFiles(repoRoot) {
|
|
119
|
-
const seen = new Set();
|
|
120
|
-
const queue = [...ENTRY_FILES];
|
|
121
|
-
|
|
122
|
-
while (queue.length > 0) {
|
|
123
|
-
const rel = queue.shift();
|
|
124
|
-
if (!rel || seen.has(rel)) {
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
if (!fs.existsSync(path.join(repoRoot, rel))) {
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
seen.add(rel);
|
|
131
|
-
for (const next of collectRequiresFromFile(repoRoot, rel)) {
|
|
132
|
-
if (!seen.has(next)) {
|
|
133
|
-
queue.push(next);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
for (const dir of SUPPLEMENTAL_DIRS) {
|
|
139
|
-
addDirectoryFiles(dir, repoRoot, seen);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return [...seen].sort().filter((rel) => !STAGING_SKIP_FILES.includes(rel));
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* @param {string} relPath
|
|
147
|
-
* @returns {boolean}
|
|
148
|
-
*/
|
|
149
|
-
function isForbiddenManifestPath(relPath) {
|
|
150
|
-
const normalized = relPath.split(path.sep).join('/');
|
|
151
|
-
for (const prefix of MANIFEST_FORBIDDEN_PREFIXES) {
|
|
152
|
-
if (normalized === prefix.replace(/\/$/, '') || normalized.startsWith(prefix)) {
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
if (normalized.endsWith('.md') && normalized.startsWith('lib/')) {
|
|
157
|
-
if (normalized.startsWith('lib/programmatic/help-content/')) {
|
|
158
|
-
return false;
|
|
159
|
-
}
|
|
160
|
-
return true;
|
|
161
|
-
}
|
|
162
|
-
return false;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* @param {string[]} manifest
|
|
167
|
-
* @returns {string[]}
|
|
168
|
-
*/
|
|
169
|
-
function findManifestViolations(manifest) {
|
|
170
|
-
return manifest.filter(isForbiddenManifestPath);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
module.exports = {
|
|
174
|
-
ENTRY_FILES,
|
|
175
|
-
SUPPLEMENTAL_DIRS,
|
|
176
|
-
MANIFEST_FORBIDDEN_PREFIXES,
|
|
177
|
-
STAGING_SKIP_FILES,
|
|
178
|
-
discoverRuntimeFiles,
|
|
179
|
-
findManifestViolations,
|
|
180
|
-
isForbiddenManifestPath,
|
|
181
|
-
resolveRelativeRequire,
|
|
182
|
-
collectRequiresFromFile
|
|
183
|
-
};
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Forbidden-path profiles for Docker image content gate (plan 154.3).
|
|
3
|
-
*
|
|
4
|
-
* @fileoverview Offline path checks + docker image listing
|
|
5
|
-
* @author AI Fabrix Team
|
|
6
|
-
* @version 1.0.0
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
'use strict';
|
|
10
|
-
|
|
11
|
-
const { spawnSync } = require('child_process');
|
|
12
|
-
|
|
13
|
-
/** @type {readonly string[]} */
|
|
14
|
-
const BUILDER_API_FORBIDDEN = [
|
|
15
|
-
'/app/.cursor',
|
|
16
|
-
'/app/builder',
|
|
17
|
-
'/app/integration',
|
|
18
|
-
'/app/tests',
|
|
19
|
-
'/app/docs',
|
|
20
|
-
'/app/scripts',
|
|
21
|
-
'/app/packages',
|
|
22
|
-
'/app/bin/aifabrix.js'
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
/** @type {readonly string[]} */
|
|
26
|
-
const BUILDER_API_TEMPLATE_ALLOWED_PREFIXES = [
|
|
27
|
-
'/app/templates/openapi',
|
|
28
|
-
'/app/templates/external-system'
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @param {string} profile
|
|
33
|
-
* @returns {string[]}
|
|
34
|
-
*/
|
|
35
|
-
function forbiddenPathsForProfile(profile) {
|
|
36
|
-
const normalized = String(profile || '').trim().toLowerCase();
|
|
37
|
-
if (normalized === 'builder-api') {
|
|
38
|
-
return [...BUILDER_API_FORBIDDEN];
|
|
39
|
-
}
|
|
40
|
-
throw new Error(`Unsupported profile: ${profile}`);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @param {string[]} pathsPresent
|
|
45
|
-
* @param {string[]} forbidden
|
|
46
|
-
* @returns {string[]}
|
|
47
|
-
*/
|
|
48
|
-
function findForbiddenPrefixViolations(pathsPresent, forbidden) {
|
|
49
|
-
const violations = [];
|
|
50
|
-
for (const forbiddenPath of forbidden) {
|
|
51
|
-
const prefix = forbiddenPath.replace(/\/$/, '');
|
|
52
|
-
for (const present of pathsPresent) {
|
|
53
|
-
const normalized = present.replace(/\/$/, '');
|
|
54
|
-
if (normalized === prefix || normalized.startsWith(`${prefix}/`)) {
|
|
55
|
-
violations.push(forbiddenPath);
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return violations;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* @param {string} present
|
|
65
|
-
* @returns {boolean}
|
|
66
|
-
*/
|
|
67
|
-
function isAllowedBuilderApiTemplatePath(present) {
|
|
68
|
-
const normalized = present.replace(/\/$/, '');
|
|
69
|
-
if (normalized === '/app/templates') {
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
if (!normalized.startsWith('/app/templates')) {
|
|
73
|
-
return true;
|
|
74
|
-
}
|
|
75
|
-
return BUILDER_API_TEMPLATE_ALLOWED_PREFIXES.some((prefix) => (
|
|
76
|
-
normalized === prefix || normalized.startsWith(`${prefix}/`)
|
|
77
|
-
));
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* @param {string[]} pathsPresent
|
|
82
|
-
* @returns {string[]}
|
|
83
|
-
*/
|
|
84
|
-
function findBuilderApiTemplateViolations(pathsPresent) {
|
|
85
|
-
const violations = [];
|
|
86
|
-
for (const present of pathsPresent) {
|
|
87
|
-
if (!isAllowedBuilderApiTemplatePath(present)) {
|
|
88
|
-
violations.push(present);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return violations;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* @param {string[]} pathsPresent
|
|
96
|
-
* @returns {string[]}
|
|
97
|
-
*/
|
|
98
|
-
function findBuilderApiMarkdownViolations(pathsPresent) {
|
|
99
|
-
const violations = [];
|
|
100
|
-
for (const present of pathsPresent) {
|
|
101
|
-
if (!present.endsWith('.md')) {
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
if (present.startsWith('/app/lib/')) {
|
|
105
|
-
violations.push(present);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return violations;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* @param {string} image
|
|
113
|
-
* @param {string} workdir
|
|
114
|
-
* @param {number} maxdepth
|
|
115
|
-
* @returns {string[]}
|
|
116
|
-
*/
|
|
117
|
-
function listImagePaths(image, workdir, maxdepth = 6) {
|
|
118
|
-
const proc = spawnSync(
|
|
119
|
-
'docker',
|
|
120
|
-
[
|
|
121
|
-
'run',
|
|
122
|
-
'--rm',
|
|
123
|
-
'--entrypoint',
|
|
124
|
-
'sh',
|
|
125
|
-
image,
|
|
126
|
-
'-c',
|
|
127
|
-
`find ${workdir} -mindepth 1 -maxdepth ${maxdepth} \\( -type d -o -type f \\) 2>/dev/null`
|
|
128
|
-
],
|
|
129
|
-
{ encoding: 'utf8' }
|
|
130
|
-
);
|
|
131
|
-
if (proc.status !== 0) {
|
|
132
|
-
throw new Error((proc.stderr || proc.stdout || '').trim() || `docker run failed for image ${image}`);
|
|
133
|
-
}
|
|
134
|
-
return proc.stdout.split('\n').map((line) => line.trim()).filter(Boolean);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* @param {string} image
|
|
139
|
-
* @param {string} profile
|
|
140
|
-
* @returns {string[]}
|
|
141
|
-
*/
|
|
142
|
-
function checkImage(image, profile) {
|
|
143
|
-
const normalized = String(profile || '').trim().toLowerCase();
|
|
144
|
-
const paths = listImagePaths(image, '/app');
|
|
145
|
-
const forbidden = forbiddenPathsForProfile(profile);
|
|
146
|
-
const violations = findForbiddenPrefixViolations(paths, forbidden);
|
|
147
|
-
|
|
148
|
-
if (normalized === 'builder-api') {
|
|
149
|
-
violations.push(...findBuilderApiTemplateViolations(paths));
|
|
150
|
-
violations.push(...findBuilderApiMarkdownViolations(paths));
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return [...new Set(violations)].sort();
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
module.exports = {
|
|
157
|
-
BUILDER_API_FORBIDDEN,
|
|
158
|
-
BUILDER_API_TEMPLATE_ALLOWED_PREFIXES,
|
|
159
|
-
forbiddenPathsForProfile,
|
|
160
|
-
findForbiddenPrefixViolations,
|
|
161
|
-
isAllowedBuilderApiTemplatePath,
|
|
162
|
-
findBuilderApiTemplateViolations,
|
|
163
|
-
findBuilderApiMarkdownViolations,
|
|
164
|
-
listImagePaths,
|
|
165
|
-
checkImage
|
|
166
|
-
};
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Plan actor display name (~/.aifabrix/plan-actor.yaml, shared across repos).
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
'use strict';
|
|
6
|
-
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const os = require('os');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
|
|
11
|
-
const REPO_ROOT = path.resolve(__dirname, '../..');
|
|
12
|
-
const LEGACY_REPO_ACTOR_PATH = path.join(REPO_ROOT, '.aifabrix', 'plan-actor.yaml');
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @typedef {Object} PlanActor
|
|
16
|
-
* @property {string} displayName - Human-readable validator name for plan records
|
|
17
|
-
* @property {string} [email] - Optional contact email
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* @returns {string} Absolute path to the shared ~/.aifabrix config directory
|
|
22
|
-
*/
|
|
23
|
-
function resolveAifabrixDir() {
|
|
24
|
-
if (process.env.AIFABRIX_HOME) {
|
|
25
|
-
return path.join(process.env.AIFABRIX_HOME, '.aifabrix');
|
|
26
|
-
}
|
|
27
|
-
return path.join(os.homedir(), '.aifabrix');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @returns {string} Absolute path to plan-actor.yaml (global or PLAN_ACTOR_PATH override)
|
|
32
|
-
*/
|
|
33
|
-
function resolveActorPath() {
|
|
34
|
-
if (process.env.PLAN_ACTOR_PATH) {
|
|
35
|
-
return process.env.PLAN_ACTOR_PATH;
|
|
36
|
-
}
|
|
37
|
-
return path.join(resolveAifabrixDir(), 'plan-actor.yaml');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* One-time copy from repo-local `.aifabrix/plan-actor.yaml` when global file missing.
|
|
42
|
-
* @returns {void}
|
|
43
|
-
*/
|
|
44
|
-
function migrateLegacyActorIfNeeded() {
|
|
45
|
-
const actorPath = resolveActorPath();
|
|
46
|
-
if (fs.existsSync(actorPath) || !fs.existsSync(LEGACY_REPO_ACTOR_PATH)) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
fs.mkdirSync(path.dirname(actorPath), { recursive: true });
|
|
50
|
-
fs.copyFileSync(LEGACY_REPO_ACTOR_PATH, actorPath);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* @returns {PlanActor|null} Parsed actor from disk, or null when file or displayName is missing
|
|
55
|
-
*/
|
|
56
|
-
function loadActor() {
|
|
57
|
-
migrateLegacyActorIfNeeded();
|
|
58
|
-
const actorPath = resolveActorPath();
|
|
59
|
-
if (!fs.existsSync(actorPath)) {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
const raw = fs.readFileSync(actorPath, 'utf8');
|
|
63
|
-
const nameMatch = raw.match(/^displayName:\s*"?([^"\n]+)"?\s*$/m);
|
|
64
|
-
const emailMatch = raw.match(/^email:\s*"?([^"\n]+)"?\s*$/m);
|
|
65
|
-
if (!nameMatch) {
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
const actor = { displayName: nameMatch[1].trim() };
|
|
69
|
-
if (emailMatch) {
|
|
70
|
-
actor.email = emailMatch[1].trim();
|
|
71
|
-
}
|
|
72
|
-
return actor;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* @param {string} displayName - Validator display name written to plan-actor.yaml
|
|
77
|
-
* @param {string} [email] - Optional email stored alongside the display name
|
|
78
|
-
* @returns {string} Absolute path to the written plan-actor.yaml file
|
|
79
|
-
*/
|
|
80
|
-
function saveActor(displayName, email) {
|
|
81
|
-
const actorPath = resolveActorPath();
|
|
82
|
-
fs.mkdirSync(path.dirname(actorPath), { recursive: true });
|
|
83
|
-
const lines = [`displayName: ${JSON.stringify(displayName)}`];
|
|
84
|
-
if (email) {
|
|
85
|
-
lines.push(`email: ${JSON.stringify(email)}`);
|
|
86
|
-
}
|
|
87
|
-
fs.writeFileSync(actorPath, `${lines.join('\n')}\n`, 'utf8');
|
|
88
|
-
return actorPath;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* @param {string} [overrideName] - CLI or env override; skips reading plan-actor.yaml when set
|
|
93
|
-
* @returns {PlanActor|null} Override actor, loaded actor, or null when none is configured
|
|
94
|
-
*/
|
|
95
|
-
function resolveActor(overrideName) {
|
|
96
|
-
if (overrideName) {
|
|
97
|
-
return { displayName: overrideName };
|
|
98
|
-
}
|
|
99
|
-
return loadActor();
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
module.exports = {
|
|
103
|
-
ACTOR_PATH: resolveActorPath(),
|
|
104
|
-
resolveActorPath,
|
|
105
|
-
loadActor,
|
|
106
|
-
saveActor,
|
|
107
|
-
resolveActor,
|
|
108
|
-
migrateLegacyActorIfNeeded
|
|
109
|
-
};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Plan lifecycle paths and gate policy (builder).
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
'use strict';
|
|
6
|
-
|
|
7
|
-
const path = require('path');
|
|
8
|
-
|
|
9
|
-
const REPO_ROOT = path.resolve(__dirname, '../..');
|
|
10
|
-
const PLANS_DIR = path.join(REPO_ROOT, '.cursor/plans');
|
|
11
|
-
|
|
12
|
-
module.exports = {
|
|
13
|
-
REPO_ROOT,
|
|
14
|
-
PLANS_DIR,
|
|
15
|
-
DONE_DIR: path.join(PLANS_DIR, 'Done'),
|
|
16
|
-
REPORT_DIR: path.join(REPO_ROOT, 'temp/plan-validation'),
|
|
17
|
-
REQUIRED_SKILLS: ['builder-validate-implementation'],
|
|
18
|
-
STRICT_FRONTMATTER: false,
|
|
19
|
-
REQUIRE_APPROVAL_TO_ARCHIVE: true
|
|
20
|
-
};
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Plan quality gates (miso / builder — config-driven).
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
'use strict';
|
|
6
|
-
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const { loadPlanFile, hasSurface } = require('./plan-parse');
|
|
10
|
-
const { REQUIRED_SKILLS, STRICT_FRONTMATTER, REPO_ROOT } = require('./plan-config');
|
|
11
|
-
|
|
12
|
-
const SKILLS_DIR = path.join(REPO_ROOT, '.cursor/skills');
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @typedef {{ label: string, status: 'pass' | 'fail' | 'warn' | 'skip', detail?: string }} GateResult
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @param {string} label
|
|
20
|
-
* @param {'pass' | 'fail' | 'warn' | 'skip'} status
|
|
21
|
-
* @param {string} [detail]
|
|
22
|
-
* @returns {GateResult}
|
|
23
|
-
*/
|
|
24
|
-
function gate(label, status, detail) {
|
|
25
|
-
return { label, status, detail };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @returns {GateResult}
|
|
30
|
-
*/
|
|
31
|
-
function gateSkills() {
|
|
32
|
-
if (!REQUIRED_SKILLS.length) {
|
|
33
|
-
return gate('skills', 'skip', 'none configured');
|
|
34
|
-
}
|
|
35
|
-
const missing = REQUIRED_SKILLS.filter(
|
|
36
|
-
(name) => !fs.existsSync(path.join(SKILLS_DIR, name, 'SKILL.md'))
|
|
37
|
-
);
|
|
38
|
-
if (missing.length) {
|
|
39
|
-
return gate('skills', 'fail', `missing: ${missing.join(', ')}`);
|
|
40
|
-
}
|
|
41
|
-
return gate('skills', 'pass');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* @param {Record<string, unknown>} meta
|
|
46
|
-
* @returns {GateResult}
|
|
47
|
-
*/
|
|
48
|
-
function gatePlanFrontmatter(meta) {
|
|
49
|
-
const errors = [];
|
|
50
|
-
const warns = [];
|
|
51
|
-
if (!meta.name && !meta.overview) {
|
|
52
|
-
errors.push('name or overview');
|
|
53
|
-
}
|
|
54
|
-
if (!Array.isArray(meta.todos) || meta.todos.length === 0) {
|
|
55
|
-
errors.push('todos');
|
|
56
|
-
}
|
|
57
|
-
if (STRICT_FRONTMATTER) {
|
|
58
|
-
if (!meta.name) {
|
|
59
|
-
errors.push('name');
|
|
60
|
-
}
|
|
61
|
-
if (!meta.overview) {
|
|
62
|
-
errors.push('overview');
|
|
63
|
-
}
|
|
64
|
-
if (!meta.status) {
|
|
65
|
-
errors.push('status');
|
|
66
|
-
}
|
|
67
|
-
if (!meta.planType) {
|
|
68
|
-
errors.push('planType');
|
|
69
|
-
}
|
|
70
|
-
if (!meta.createdBy) {
|
|
71
|
-
errors.push('createdBy');
|
|
72
|
-
}
|
|
73
|
-
if (meta.planType === 'code' && !Array.isArray(meta.surfaces)) {
|
|
74
|
-
errors.push('surfaces');
|
|
75
|
-
}
|
|
76
|
-
} else if (!meta.createdBy) {
|
|
77
|
-
warns.push('createdBy');
|
|
78
|
-
}
|
|
79
|
-
if (errors.length) {
|
|
80
|
-
return gate('plan-frontmatter', 'fail', `missing: ${errors.join(', ')}`);
|
|
81
|
-
}
|
|
82
|
-
if (warns.length) {
|
|
83
|
-
return gate('plan-frontmatter', 'warn', `missing: ${warns.join(', ')}`);
|
|
84
|
-
}
|
|
85
|
-
return gate('plan-frontmatter', 'pass');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* @param {Record<string, unknown>} meta
|
|
90
|
-
* @returns {GateResult}
|
|
91
|
-
*/
|
|
92
|
-
function gateApiTier(meta) {
|
|
93
|
-
if (!hasSurface(meta, 'api')) {
|
|
94
|
-
return gate('api-tier', 'skip', 'no api surface');
|
|
95
|
-
}
|
|
96
|
-
const tiers = meta.apiTiers;
|
|
97
|
-
if (!Array.isArray(tiers) || tiers.length === 0) {
|
|
98
|
-
return gate('api-tier', 'warn', 'api surface without apiTiers');
|
|
99
|
-
}
|
|
100
|
-
return gate('api-tier', 'pass');
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* @param {Array<{ id: string, status: string, content: string }>} todos
|
|
105
|
-
*/
|
|
106
|
-
function auditTodos(todos) {
|
|
107
|
-
const blockingPending = todos.filter(
|
|
108
|
-
(t) => t.status === 'pending' || t.status === 'in_progress'
|
|
109
|
-
);
|
|
110
|
-
const manualPending = todos.filter(
|
|
111
|
-
(t) =>
|
|
112
|
-
(t.status === 'pending' || t.status === 'in_progress') &&
|
|
113
|
-
/manual|pilot|proof|e2e smoke|live test|business validation/i.test(t.content)
|
|
114
|
-
);
|
|
115
|
-
return { blockingPending, manualPending };
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* @param {string} planPath
|
|
120
|
-
*/
|
|
121
|
-
function runAllGates(planPath) {
|
|
122
|
-
const loaded = loadPlanFile(planPath);
|
|
123
|
-
if (!loaded) {
|
|
124
|
-
return {
|
|
125
|
-
gates: [gate('plan-parse', 'fail', 'invalid frontmatter')],
|
|
126
|
-
todos: [],
|
|
127
|
-
blockingPending: [],
|
|
128
|
-
manualPending: []
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const { meta } = loaded;
|
|
133
|
-
const todos = Array.isArray(meta.todos) ? meta.todos : [];
|
|
134
|
-
const gates = [
|
|
135
|
-
gateSkills(),
|
|
136
|
-
gatePlanFrontmatter(meta),
|
|
137
|
-
gateApiTier(meta),
|
|
138
|
-
gate('todos', todos.length ? 'pass' : 'fail', `${todos.length} todo(s)`)
|
|
139
|
-
];
|
|
140
|
-
|
|
141
|
-
const { blockingPending, manualPending } = auditTodos(
|
|
142
|
-
todos.map((t) => ({
|
|
143
|
-
id: String(t.id || ''),
|
|
144
|
-
status: String(t.status || 'pending'),
|
|
145
|
-
content: String(t.content || '')
|
|
146
|
-
}))
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
return { gates, todos, blockingPending, manualPending };
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
module.exports = {
|
|
153
|
-
runAllGates
|
|
154
|
-
};
|