@wairon/cli 5.0.2-dev.14 → 5.0.2-dev.15
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/dist/cli/index.js +259 -43
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +38 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -65,7 +65,7 @@ var init_defaults = __esm({
|
|
|
65
65
|
copilot: ".github/prompts",
|
|
66
66
|
codex: ".codex/agents"
|
|
67
67
|
};
|
|
68
|
-
WAIRON_VERSION = "5.0.2-dev.
|
|
68
|
+
WAIRON_VERSION = "5.0.2-dev.15";
|
|
69
69
|
GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
70
70
|
ARCHITECT_AGENT_ID = "agent-architect";
|
|
71
71
|
ARCHITECT_TEMPLATE_ID = "architect";
|
|
@@ -458,7 +458,7 @@ var init_domain = __esm({
|
|
|
458
458
|
});
|
|
459
459
|
|
|
460
460
|
// src/models/project.ts
|
|
461
|
-
var import_zod3, BuiltinTargetConfigSchema, CustomTargetConfigSchema, TargetConfigSchema, NamingRuleConfigSchema, DocumentationRuleConfigSchema, ComplexityRuleConfigSchema, DesignDepthSchema, RulesConfigSchema, PathsConfigSchema, ProjectConfigSchema;
|
|
461
|
+
var import_zod3, BuiltinTargetConfigSchema, CustomTargetConfigSchema, TargetConfigSchema, NamingRuleConfigSchema, DocumentationRuleConfigSchema, ComplexityRuleConfigSchema, DesignDepthSchema, RulesConfigSchema, PathsConfigSchema, ProfileSelectionSubjectSchema, ProjectProfileSelectionSchema, ProjectConfigSchema;
|
|
462
462
|
var init_project = __esm({
|
|
463
463
|
"src/models/project.ts"() {
|
|
464
464
|
"use strict";
|
|
@@ -582,6 +582,24 @@ var init_project = __esm({
|
|
|
582
582
|
/** Base directory containing SDD specification files, relative to project root */
|
|
583
583
|
specsDir: import_zod3.z.string().default(".wai/specs")
|
|
584
584
|
});
|
|
585
|
+
ProfileSelectionSubjectSchema = import_zod3.z.object({
|
|
586
|
+
userId: import_zod3.z.string(),
|
|
587
|
+
kind: import_zod3.z.string(),
|
|
588
|
+
issuer: import_zod3.z.string(),
|
|
589
|
+
externalSubject: import_zod3.z.string().optional(),
|
|
590
|
+
displayName: import_zod3.z.string().optional(),
|
|
591
|
+
email: import_zod3.z.string().optional()
|
|
592
|
+
});
|
|
593
|
+
ProjectProfileSelectionSchema = import_zod3.z.object({
|
|
594
|
+
/** Selected architectural profile ids. The first resolvable one is applied as projectType. */
|
|
595
|
+
profileIds: import_zod3.z.array(import_zod3.z.string()).default([]),
|
|
596
|
+
/** Pack names the governing policy requires for this project. */
|
|
597
|
+
requiredPackNames: import_zod3.z.array(import_zod3.z.string()).default([]),
|
|
598
|
+
/** Pack names applied by default unless explicitly overridden. */
|
|
599
|
+
defaultPackNames: import_zod3.z.array(import_zod3.z.string()).optional(),
|
|
600
|
+
selectedBy: ProfileSelectionSubjectSchema.optional(),
|
|
601
|
+
selectedAt: import_zod3.z.string()
|
|
602
|
+
});
|
|
585
603
|
ProjectConfigSchema = import_zod3.z.object({
|
|
586
604
|
/**
|
|
587
605
|
* Schema version — used to detect incompatible config formats in future
|
|
@@ -622,6 +640,13 @@ var init_project = __esm({
|
|
|
622
640
|
useGlobalPacks: import_zod3.z.boolean().default(true)
|
|
623
641
|
}).optional(),
|
|
624
642
|
paths: PathsConfigSchema.default({}),
|
|
643
|
+
/**
|
|
644
|
+
* The profile/pack selection a hosted policy workflow applied to this project.
|
|
645
|
+
* The RECORD of what was chosen; `projectType` above is what actually governs
|
|
646
|
+
* validation. Modeled so the parse/write round trip preserves it (see
|
|
647
|
+
* ProjectProfileSelectionSchema).
|
|
648
|
+
*/
|
|
649
|
+
profileSelection: ProjectProfileSelectionSchema.optional(),
|
|
625
650
|
/**
|
|
626
651
|
* Path to a directory containing org/user-level default templates.
|
|
627
652
|
* Resolved before built-in templates but after project-local templates.
|
|
@@ -7313,7 +7338,7 @@ var init_extensions = __esm({
|
|
|
7313
7338
|
});
|
|
7314
7339
|
|
|
7315
7340
|
// src/core/rules/types.ts
|
|
7316
|
-
var BUILTIN_PROFILES;
|
|
7341
|
+
var BUILTIN_PROFILES, PROJECT_KINDS;
|
|
7317
7342
|
var init_types = __esm({
|
|
7318
7343
|
"src/core/rules/types.ts"() {
|
|
7319
7344
|
"use strict";
|
|
@@ -7326,6 +7351,7 @@ var init_types = __esm({
|
|
|
7326
7351
|
"realtime-embedded",
|
|
7327
7352
|
"plc-cyclic"
|
|
7328
7353
|
];
|
|
7354
|
+
PROJECT_KINDS = ["fullstack", "system-of-systems", "monorepo"];
|
|
7329
7355
|
}
|
|
7330
7356
|
});
|
|
7331
7357
|
|
|
@@ -10509,14 +10535,14 @@ var init_declarative_assertions = __esm({
|
|
|
10509
10535
|
});
|
|
10510
10536
|
|
|
10511
10537
|
// src/core/rules/profiles.ts
|
|
10512
|
-
var BACKEND_LIKE, FRONTEND_LIKE,
|
|
10538
|
+
var BACKEND_LIKE, FRONTEND_LIKE, PROJECT_KINDS2, profilesRule;
|
|
10513
10539
|
var init_profiles = __esm({
|
|
10514
10540
|
"src/core/rules/profiles.ts"() {
|
|
10515
10541
|
"use strict";
|
|
10516
10542
|
init_types();
|
|
10517
10543
|
BACKEND_LIKE = /* @__PURE__ */ new Set(["backend", "lowlevel-os", "game-ecs", "realtime-embedded", "plc-cyclic"]);
|
|
10518
10544
|
FRONTEND_LIKE = /* @__PURE__ */ new Set(["frontend-reactive", "frontend-controller"]);
|
|
10519
|
-
|
|
10545
|
+
PROJECT_KINDS2 = new Set(PROJECT_KINDS);
|
|
10520
10546
|
profilesRule = {
|
|
10521
10547
|
name: "architectural-profiles",
|
|
10522
10548
|
description: "Per-profile stereotype constraints: View/FeatureComponent/RouterComponent only in frontend profiles; Actor/Supervisor forbidden in plc-cyclic (single scan cycle); Actor/Supervisor in frontend profiles warned. Extension packs may register custom profiles (family + forbidden/discouraged stereotype lists); unknown profile names are flagged.",
|
|
@@ -10540,7 +10566,7 @@ var init_profiles = __esm({
|
|
|
10540
10566
|
);
|
|
10541
10567
|
}
|
|
10542
10568
|
}
|
|
10543
|
-
if (!registered.has(ctx.projectType) && !
|
|
10569
|
+
if (!registered.has(ctx.projectType) && !PROJECT_KINDS2.has(ctx.projectType)) {
|
|
10544
10570
|
ctx.addIssue(
|
|
10545
10571
|
"warning",
|
|
10546
10572
|
"UNKNOWN_PROFILE",
|
|
@@ -27126,7 +27152,15 @@ var hostCore = {
|
|
|
27126
27152
|
/** The ids of wairon's built-in architectural profiles, read from the core rules
|
|
27127
27153
|
* registry's built-in profile set (BUILTIN_PROFILES) — a pure, side-effect-free
|
|
27128
27154
|
* read of a bundled constant. */
|
|
27129
|
-
builtinProfileIds: () => [...BUILTIN_PROFILES]
|
|
27155
|
+
builtinProfileIds: () => [...BUILTIN_PROFILES],
|
|
27156
|
+
/** The ids of wairon's built-in COMPOSITE PROJECT KINDS, read from the core
|
|
27157
|
+
* rules registry's bundled constant (PROJECT_KINDS) — a pure, side-effect-free
|
|
27158
|
+
* read. The counterpart of builtinProfileIds: legal projectType values that
|
|
27159
|
+
* are not architectural profiles and carry no profile doctrine of their own,
|
|
27160
|
+
* so the hosted profile-application path recognizes a project kind as
|
|
27161
|
+
* resolvable-as-is (no contributing pack to adopt) instead of refusing it as
|
|
27162
|
+
* an unknown profile. */
|
|
27163
|
+
builtinProjectKinds: () => [...PROJECT_KINDS]
|
|
27130
27164
|
};
|
|
27131
27165
|
function resolveContainedProjectPath(projectRoot2, projectPath) {
|
|
27132
27166
|
return assertContainedProjectPath(projectRoot2, projectPath);
|
|
@@ -27747,6 +27781,35 @@ function storeListGlobalPacks() {
|
|
|
27747
27781
|
);
|
|
27748
27782
|
return [...instance, ...image];
|
|
27749
27783
|
}
|
|
27784
|
+
function scanGlobalPackProfiles() {
|
|
27785
|
+
const out = [];
|
|
27786
|
+
for (const dir of [hostCore.globalPacksDir(), imagePacksDir()]) {
|
|
27787
|
+
for (const full of hostCore.discoverPacks(dir)) {
|
|
27788
|
+
try {
|
|
27789
|
+
const loaded = hostCore.loadExtensionPacks([{ ref: full, scope: "global" }], path45.dirname(full));
|
|
27790
|
+
if (loaded.errors.length) continue;
|
|
27791
|
+
const source = loaded.packNames[0] ?? path45.basename(full);
|
|
27792
|
+
for (const [id, def] of Object.entries(loaded.profiles)) out.push({ id, source, family: def.family });
|
|
27793
|
+
} catch {
|
|
27794
|
+
}
|
|
27795
|
+
}
|
|
27796
|
+
}
|
|
27797
|
+
return out;
|
|
27798
|
+
}
|
|
27799
|
+
function scanProjectPackProfiles() {
|
|
27800
|
+
const root = getProjectRoot();
|
|
27801
|
+
const out = [];
|
|
27802
|
+
for (const ref of loadProjectConfig().extensions?.packs ?? []) {
|
|
27803
|
+
try {
|
|
27804
|
+
const loaded = hostCore.loadExtensionPacks([{ ref, scope: "project" }], root);
|
|
27805
|
+
if (loaded.errors.length) continue;
|
|
27806
|
+
const source = loaded.packNames[0] ?? stem(ref);
|
|
27807
|
+
for (const [id, def] of Object.entries(loaded.profiles)) out.push({ id, source, family: def.family });
|
|
27808
|
+
} catch {
|
|
27809
|
+
}
|
|
27810
|
+
}
|
|
27811
|
+
return out;
|
|
27812
|
+
}
|
|
27750
27813
|
function storeListAvailableProfiles() {
|
|
27751
27814
|
const out = [];
|
|
27752
27815
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -27757,19 +27820,21 @@ function storeListAvailableProfiles() {
|
|
|
27757
27820
|
out.push(family ? { id, source, family } : { id, source });
|
|
27758
27821
|
};
|
|
27759
27822
|
for (const id of hostCore.builtinProfileIds()) emit(id, "builtin");
|
|
27760
|
-
const
|
|
27761
|
-
|
|
27762
|
-
|
|
27763
|
-
|
|
27764
|
-
|
|
27765
|
-
|
|
27766
|
-
|
|
27767
|
-
|
|
27768
|
-
|
|
27769
|
-
|
|
27823
|
+
for (const c of scanGlobalPackProfiles()) emit(c.id, c.source, c.family);
|
|
27824
|
+
return out;
|
|
27825
|
+
}
|
|
27826
|
+
function storeListProjectProfiles() {
|
|
27827
|
+
const out = [];
|
|
27828
|
+
const seen = /* @__PURE__ */ new Set();
|
|
27829
|
+
const emit = (id, source, installed, family) => {
|
|
27830
|
+
const key = JSON.stringify([id, source]);
|
|
27831
|
+
if (seen.has(key)) return;
|
|
27832
|
+
seen.add(key);
|
|
27833
|
+
out.push({ id, source, ...family ? { family } : {}, installed });
|
|
27770
27834
|
};
|
|
27771
|
-
|
|
27772
|
-
|
|
27835
|
+
for (const id of hostCore.builtinProfileIds()) emit(id, "builtin", true);
|
|
27836
|
+
for (const c of scanProjectPackProfiles()) emit(c.id, c.source, true, c.family);
|
|
27837
|
+
for (const c of scanGlobalPackProfiles()) emit(c.id, c.source, false, c.family);
|
|
27773
27838
|
return out;
|
|
27774
27839
|
}
|
|
27775
27840
|
function readPackContent(full) {
|
|
@@ -27962,6 +28027,10 @@ function listAvailableProfiles(cfg, credential) {
|
|
|
27962
28027
|
requirePrincipal2(cfg, credential);
|
|
27963
28028
|
return storeListAvailableProfiles();
|
|
27964
28029
|
}
|
|
28030
|
+
function listProjectProfiles(cfg, credential, project2) {
|
|
28031
|
+
requireCap(cfg, credential, "project:read", "project", project2, "Forbidden \u2014 listing a project's selectable profiles requires project:read over the project");
|
|
28032
|
+
return executeApprovedListProjectProfiles(cfg, project2);
|
|
28033
|
+
}
|
|
27965
28034
|
function listAdoptableProjectPacks(cfg, credential, project2) {
|
|
27966
28035
|
requireCap(cfg, credential, "project:read", "project", project2, "Forbidden \u2014 listing adoptable packs requires project:read over the project");
|
|
27967
28036
|
return storeListGlobalPacks();
|
|
@@ -27984,6 +28053,26 @@ function executeApprovedInstallProjectPack(cfg, project2, name, content) {
|
|
|
27984
28053
|
function executeApprovedResolveGlobalPacks(names) {
|
|
27985
28054
|
return storeResolveGlobalPacks(names);
|
|
27986
28055
|
}
|
|
28056
|
+
function executeApprovedListProjectProfiles(cfg, project2) {
|
|
28057
|
+
return runWithProjectRoot(boundProject2(cfg, project2), () => storeListProjectProfiles());
|
|
28058
|
+
}
|
|
28059
|
+
function executeApprovedEnsureProfileInstalled(cfg, project2, profileId) {
|
|
28060
|
+
if (hostCore.builtinProjectKinds().includes(profileId) || hostCore.builtinProfileIds().includes(profileId)) {
|
|
28061
|
+
return { profileId, source: "builtin" };
|
|
28062
|
+
}
|
|
28063
|
+
const contributors = executeApprovedListProjectProfiles(cfg, project2).filter((p) => p.id === profileId);
|
|
28064
|
+
const installed = contributors.find((p) => p.installed);
|
|
28065
|
+
if (installed) return { profileId, source: installed.source };
|
|
28066
|
+
const adoptable = contributors[0];
|
|
28067
|
+
const resolved = adoptable ? executeApprovedResolveGlobalPacks([adoptable.source]).resolved[0] : void 0;
|
|
28068
|
+
if (!resolved) {
|
|
28069
|
+
throw new Error(
|
|
28070
|
+
`Unknown profile "${profileId}" \u2014 no built-in profile or project kind carries it, no pack registered in project "${project2}" contributes it, and no server-global pack (mutable instance tier or immutable image tier) contributes it. Writing an unresolvable id as the projectType would silently disable the whole profile doctrine (UNKNOWN_PROFILE), so it is refused instead of applied.`
|
|
28071
|
+
);
|
|
28072
|
+
}
|
|
28073
|
+
executeApprovedInstallProjectPack(cfg, project2, resolved.name, resolved.content);
|
|
28074
|
+
return { profileId, source: resolved.name, adoptedPackName: resolved.name };
|
|
28075
|
+
}
|
|
27987
28076
|
function removeProjectPack(cfg, credential, project2, name) {
|
|
27988
28077
|
requireCap(cfg, credential, "project:admin", "project", project2, "Forbidden \u2014 removing a project pack requires project:admin over the project");
|
|
27989
28078
|
runWithProjectRoot(boundProject2(cfg, project2), () => storeRemoveProjectPack(name));
|
|
@@ -28978,6 +29067,40 @@ function requestPackNames(request) {
|
|
|
28978
29067
|
if (!sel) return [];
|
|
28979
29068
|
return [.../* @__PURE__ */ new Set([...sel.requiredPackNames ?? [], ...sel.defaultPackNames ?? []])];
|
|
28980
29069
|
}
|
|
29070
|
+
function classifyProfile(projectType, catalog) {
|
|
29071
|
+
if (hostCore.builtinProfileIds().includes(projectType) || hostCore.builtinProjectKinds().includes(projectType)) {
|
|
29072
|
+
return { source: "builtin", resolvable: true };
|
|
29073
|
+
}
|
|
29074
|
+
const installed = catalog.find((p) => p.id === projectType && p.installed);
|
|
29075
|
+
if (installed) return { source: installed.source, resolvable: true };
|
|
29076
|
+
return { resolvable: false };
|
|
29077
|
+
}
|
|
29078
|
+
function firstApplicableProfileId(candidates, catalog) {
|
|
29079
|
+
const kinds = hostCore.builtinProjectKinds();
|
|
29080
|
+
const catalogIds = new Set(catalog.map((p) => p.id));
|
|
29081
|
+
return candidates.find((id) => kinds.includes(id) || catalogIds.has(id));
|
|
29082
|
+
}
|
|
29083
|
+
function unappliedIds(selectedProfileIds, governingProfileId) {
|
|
29084
|
+
return selectedProfileIds.filter((id) => id !== governingProfileId);
|
|
29085
|
+
}
|
|
29086
|
+
function foldAppliedProfile(root, profileId, actor) {
|
|
29087
|
+
const recorded = readProjectProfileSelection(root);
|
|
29088
|
+
const folded = {
|
|
29089
|
+
profileIds: [profileId, ...unappliedIds(recorded?.profileIds ?? [], profileId)],
|
|
29090
|
+
requiredPackNames: recorded?.requiredPackNames ?? [],
|
|
29091
|
+
selectedBy: actor,
|
|
29092
|
+
selectedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
29093
|
+
};
|
|
29094
|
+
if (recorded?.defaultPackNames) folded.defaultPackNames = recorded.defaultPackNames;
|
|
29095
|
+
recordProjectProfileSelection(root, folded);
|
|
29096
|
+
return folded;
|
|
29097
|
+
}
|
|
29098
|
+
function overridingSubsystemIds(root) {
|
|
29099
|
+
return runWithProjectRoot(
|
|
29100
|
+
root,
|
|
29101
|
+
() => hostCore.loadSubsystemSpecs().filter((s) => !!s.profile).map((s) => s.id)
|
|
29102
|
+
);
|
|
29103
|
+
}
|
|
28981
29104
|
function resolvedSelection(request, policy, selectedBy) {
|
|
28982
29105
|
const sel = request.profileSelection;
|
|
28983
29106
|
const selection = {
|
|
@@ -28996,7 +29119,8 @@ function buildEvaluation(input) {
|
|
|
28996
29119
|
selectedProfileIds,
|
|
28997
29120
|
hasSelection,
|
|
28998
29121
|
countMissingPacksAsViolation,
|
|
28999
|
-
requiredDefaultResolution
|
|
29122
|
+
requiredDefaultResolution,
|
|
29123
|
+
governingProfileId
|
|
29000
29124
|
} = input;
|
|
29001
29125
|
const present = new Set(presentPackNames);
|
|
29002
29126
|
let missingPackNames;
|
|
@@ -29017,6 +29141,7 @@ function buildEvaluation(input) {
|
|
|
29017
29141
|
const allowed = policy.allowedProfileIds;
|
|
29018
29142
|
const disallowedProfileIds = allowed && allowed.length > 0 ? selectedProfileIds.filter((id) => !allowed.includes(id)) : [];
|
|
29019
29143
|
const selectionRequiredUnmet = policy.requireProfileSelection && !hasSelection;
|
|
29144
|
+
const unappliedProfileIds = governingProfileId ? unappliedIds(selectedProfileIds, governingProfileId) : [];
|
|
29020
29145
|
const messages = [];
|
|
29021
29146
|
if (selectionRequiredUnmet) {
|
|
29022
29147
|
messages.push("Profile selection is required by policy but none was provided.");
|
|
@@ -29028,16 +29153,24 @@ function buildEvaluation(input) {
|
|
|
29028
29153
|
for (const n of blockedPackNames) messages.push(`Pack "${n}" is blocked by policy.`);
|
|
29029
29154
|
for (const id of missingProfileIds) messages.push(`Required profile "${id}" is not selected.`);
|
|
29030
29155
|
for (const id of disallowedProfileIds) messages.push(`Profile "${id}" is not permitted by policy.`);
|
|
29156
|
+
for (const id of unappliedProfileIds) {
|
|
29157
|
+
messages.push(
|
|
29158
|
+
`Selected profile "${id}" is recorded but does not govern the project (projectType is "${governingProfileId}") \u2014 a project has exactly one governing profile.`
|
|
29159
|
+
);
|
|
29160
|
+
}
|
|
29031
29161
|
const violation = selectionRequiredUnmet || blockedPackNames.length > 0 || missingProfileIds.length > 0 || disallowedProfileIds.length > 0 || countMissingPacksAsViolation && (missingPackNames.length > 0 || unresolvedPacks.length > 0);
|
|
29032
|
-
|
|
29162
|
+
const result = {
|
|
29033
29163
|
compliant: !violation,
|
|
29034
29164
|
mode: policy.enforcementMode,
|
|
29035
29165
|
missingPackNames,
|
|
29036
29166
|
blockedPackNames,
|
|
29037
29167
|
missingProfileIds,
|
|
29038
29168
|
unresolvedPacks,
|
|
29169
|
+
unappliedProfileIds,
|
|
29039
29170
|
messages
|
|
29040
29171
|
};
|
|
29172
|
+
if (governingProfileId) result.governingProfileId = governingProfileId;
|
|
29173
|
+
return result;
|
|
29041
29174
|
}
|
|
29042
29175
|
function performInit(cfg, request, principal) {
|
|
29043
29176
|
const policy = effectivePolicy(cfg.dataDir);
|
|
@@ -29057,17 +29190,24 @@ function performInit(cfg, request, principal) {
|
|
|
29057
29190
|
request.ownerUnitId,
|
|
29058
29191
|
principal ? principalSubject3(principal) : void 0
|
|
29059
29192
|
);
|
|
29060
|
-
|
|
29061
|
-
|
|
29062
|
-
|
|
29063
|
-
|
|
29064
|
-
|
|
29065
|
-
|
|
29066
|
-
...requestPackNames(request)
|
|
29067
|
-
])
|
|
29068
|
-
);
|
|
29193
|
+
const packResolution = executeApprovedResolveGlobalPacks([
|
|
29194
|
+
...policy.requiredGlobalPacks,
|
|
29195
|
+
...policy.defaultProjectPacks,
|
|
29196
|
+
...requestPackNames(request)
|
|
29197
|
+
]);
|
|
29198
|
+
installResolvedPacks(cfg, record2.id, packResolution);
|
|
29069
29199
|
const selectedBy = principal ? principalSubject3(principal) : void 0;
|
|
29070
|
-
|
|
29200
|
+
const selection = resolvedSelection(request, policy, selectedBy);
|
|
29201
|
+
recordProjectProfileSelection(record2.rootPath, selection);
|
|
29202
|
+
const catalog = executeApprovedListProjectProfiles(cfg, record2.id);
|
|
29203
|
+
const appliedProfileId = firstApplicableProfileId(selection.profileIds, catalog);
|
|
29204
|
+
let appliedSource;
|
|
29205
|
+
if (appliedProfileId) {
|
|
29206
|
+
const application = executeApprovedEnsureProfileInstalled(cfg, record2.id, appliedProfileId);
|
|
29207
|
+
writeProjectType(record2.rootPath, application.profileId);
|
|
29208
|
+
appliedSource = application.source;
|
|
29209
|
+
}
|
|
29210
|
+
const unapplied = appliedProfileId ? unappliedIds(selection.profileIds, appliedProfileId) : [...selection.profileIds];
|
|
29071
29211
|
const actor = principal ? principalSubject3(principal) : SYSTEM_SUBJECT;
|
|
29072
29212
|
tryAppendAudit2(
|
|
29073
29213
|
cfg,
|
|
@@ -29076,7 +29216,18 @@ function performInit(cfg, request, principal) {
|
|
|
29076
29216
|
"project.init.policy",
|
|
29077
29217
|
"info",
|
|
29078
29218
|
"project",
|
|
29079
|
-
{
|
|
29219
|
+
{
|
|
29220
|
+
target: record2.id,
|
|
29221
|
+
projectId: record2.id,
|
|
29222
|
+
metadata: JSON.stringify({
|
|
29223
|
+
...appliedProfileId ? { appliedProfileId, profileSource: appliedSource } : {
|
|
29224
|
+
appliedProfileId: null,
|
|
29225
|
+
profileNotApplied: selection.profileIds.length === 0 ? "no profile was selected \u2014 the default projectType stands" : "no selected profile is resolvable on this instance \u2014 the default projectType stands"
|
|
29226
|
+
},
|
|
29227
|
+
...unapplied.length > 0 ? { unappliedProfileIds: unapplied } : {},
|
|
29228
|
+
...packResolution.unresolved.length > 0 ? { unresolvedPacks: packResolution.unresolved } : {}
|
|
29229
|
+
})
|
|
29230
|
+
},
|
|
29080
29231
|
principal?.tokenId
|
|
29081
29232
|
)
|
|
29082
29233
|
);
|
|
@@ -29117,6 +29268,7 @@ function evaluateProjectPolicy(cfg, credential, projectId) {
|
|
|
29117
29268
|
const root = resolveProjectRoot(cfg.dataDir, principal, projectId);
|
|
29118
29269
|
if (!root) throw new Error(`Unknown project "${projectId}".`);
|
|
29119
29270
|
const policy = effectivePolicy(cfg.dataDir);
|
|
29271
|
+
const governingProfileId = readProjectType(root);
|
|
29120
29272
|
const selection = readProjectProfileSelection(root);
|
|
29121
29273
|
return buildEvaluation({
|
|
29122
29274
|
policy,
|
|
@@ -29124,7 +29276,8 @@ function evaluateProjectPolicy(cfg, credential, projectId) {
|
|
|
29124
29276
|
selectedProfileIds: selection?.profileIds ?? [],
|
|
29125
29277
|
hasSelection: !!selection,
|
|
29126
29278
|
countMissingPacksAsViolation: true,
|
|
29127
|
-
requiredDefaultResolution: executeApprovedResolveGlobalPacks(requiredDefaultNames(policy))
|
|
29279
|
+
requiredDefaultResolution: executeApprovedResolveGlobalPacks(requiredDefaultNames(policy)),
|
|
29280
|
+
governingProfileId
|
|
29128
29281
|
});
|
|
29129
29282
|
}
|
|
29130
29283
|
function reconcileProjectPolicy(cfg, credential, projectId) {
|
|
@@ -29139,20 +29292,41 @@ function reconcileProjectPolicy(cfg, credential, projectId) {
|
|
|
29139
29292
|
const policy = effectivePolicy(cfg.dataDir);
|
|
29140
29293
|
const selection = readProjectProfileSelection(root);
|
|
29141
29294
|
const resolution = executeApprovedResolveGlobalPacks(requiredDefaultNames(policy));
|
|
29142
|
-
|
|
29143
|
-
const installedSet = new Set(installed);
|
|
29295
|
+
const installedSet = new Set(installedPackNames(cfg, projectId));
|
|
29144
29296
|
const toApply = resolution.resolved.filter((p) => !installedSet.has(p.name));
|
|
29297
|
+
const appliedPackNames = toApply.map((p) => p.name);
|
|
29145
29298
|
if (toApply.length > 0) {
|
|
29146
29299
|
installResolvedPacks(cfg, projectId, { resolved: toApply, unresolved: [] });
|
|
29147
|
-
|
|
29300
|
+
}
|
|
29301
|
+
const catalog = executeApprovedListProjectProfiles(cfg, projectId);
|
|
29302
|
+
const previousProfileId = readProjectType(root);
|
|
29303
|
+
let governingProfileId = previousProfileId;
|
|
29304
|
+
const requiredProfileIds = policy.requiredProfileIds ?? [];
|
|
29305
|
+
const policyUnsatisfied = requiredProfileIds.length > 0 && !requiredProfileIds.includes(governingProfileId);
|
|
29306
|
+
const governingUnresolvable = !classifyProfile(governingProfileId, catalog).resolvable;
|
|
29307
|
+
let repairedProfileId;
|
|
29308
|
+
let selectedProfileIds = selection?.profileIds ?? [];
|
|
29309
|
+
if (policyUnsatisfied || governingUnresolvable) {
|
|
29310
|
+
const target = firstApplicableProfileId(
|
|
29311
|
+
[...requiredProfileIds, ...selection?.profileIds ?? []],
|
|
29312
|
+
catalog
|
|
29313
|
+
);
|
|
29314
|
+
if (target) {
|
|
29315
|
+
const application = executeApprovedEnsureProfileInstalled(cfg, projectId, target);
|
|
29316
|
+
writeProjectType(root, application.profileId);
|
|
29317
|
+
governingProfileId = application.profileId;
|
|
29318
|
+
repairedProfileId = application.profileId;
|
|
29319
|
+
selectedProfileIds = foldAppliedProfile(root, application.profileId, principalSubject3(principal)).profileIds;
|
|
29320
|
+
}
|
|
29148
29321
|
}
|
|
29149
29322
|
const result = buildEvaluation({
|
|
29150
29323
|
policy,
|
|
29151
|
-
presentPackNames:
|
|
29152
|
-
selectedProfileIds
|
|
29324
|
+
presentPackNames: installedPackNames(cfg, projectId),
|
|
29325
|
+
selectedProfileIds,
|
|
29153
29326
|
hasSelection: !!selection,
|
|
29154
29327
|
countMissingPacksAsViolation: true,
|
|
29155
|
-
requiredDefaultResolution: resolution
|
|
29328
|
+
requiredDefaultResolution: resolution,
|
|
29329
|
+
governingProfileId
|
|
29156
29330
|
});
|
|
29157
29331
|
tryAppendAudit2(
|
|
29158
29332
|
cfg,
|
|
@@ -29161,7 +29335,15 @@ function reconcileProjectPolicy(cfg, credential, projectId) {
|
|
|
29161
29335
|
"policy.reconcile",
|
|
29162
29336
|
"info",
|
|
29163
29337
|
"policy",
|
|
29164
|
-
{
|
|
29338
|
+
{
|
|
29339
|
+
target: projectId,
|
|
29340
|
+
projectId,
|
|
29341
|
+
metadata: JSON.stringify({
|
|
29342
|
+
...appliedPackNames.length > 0 ? { appliedPackNames } : {},
|
|
29343
|
+
...repairedProfileId ? { repairedProfileId, previousProfileId } : {},
|
|
29344
|
+
...resolution.unresolved.length > 0 ? { unresolvedPacks: resolution.unresolved } : {}
|
|
29345
|
+
})
|
|
29346
|
+
},
|
|
29165
29347
|
principal.tokenId
|
|
29166
29348
|
)
|
|
29167
29349
|
);
|
|
@@ -29177,8 +29359,19 @@ function getProjectConfig(cfg, credential, projectId) {
|
|
|
29177
29359
|
const root = resolveProjectRoot(cfg.dataDir, principal, projectId);
|
|
29178
29360
|
if (!root) throw new Error(`Unknown project "${projectId}".`);
|
|
29179
29361
|
const projectType = readProjectType(root);
|
|
29362
|
+
const selection = readProjectProfileSelection(root);
|
|
29363
|
+
const classified = classifyProfile(projectType, executeApprovedListProjectProfiles(cfg, projectId));
|
|
29180
29364
|
const locked = runWithProjectRoot(root, () => hostCore.readLockRecord() !== null);
|
|
29181
|
-
|
|
29365
|
+
const overriding = overridingSubsystemIds(root);
|
|
29366
|
+
const view = {
|
|
29367
|
+
projectType,
|
|
29368
|
+
locked,
|
|
29369
|
+
profileResolvable: classified.resolvable,
|
|
29370
|
+
unappliedProfileIds: unappliedIds(selection?.profileIds ?? [], projectType),
|
|
29371
|
+
overridingSubsystemIds: overriding
|
|
29372
|
+
};
|
|
29373
|
+
if (classified.source) view.profileSource = classified.source;
|
|
29374
|
+
return view;
|
|
29182
29375
|
}
|
|
29183
29376
|
function setProjectType(cfg, credential, projectId, projectType) {
|
|
29184
29377
|
const principal = requirePrincipal4(cfg, credential);
|
|
@@ -29189,9 +29382,23 @@ function setProjectType(cfg, credential, projectId, projectType) {
|
|
|
29189
29382
|
}
|
|
29190
29383
|
const root = resolveProjectRoot(cfg.dataDir, principal, projectId);
|
|
29191
29384
|
if (!root) throw new Error(`Unknown project "${projectId}".`);
|
|
29192
|
-
|
|
29385
|
+
const application = executeApprovedEnsureProfileInstalled(cfg, projectId, projectType);
|
|
29386
|
+
writeProjectType(root, application.profileId);
|
|
29387
|
+
const folded = foldAppliedProfile(root, application.profileId, principalSubject3(principal));
|
|
29388
|
+
const remainder = folded.profileIds.slice(1);
|
|
29193
29389
|
const locked = runWithProjectRoot(root, () => hostCore.readLockRecord() !== null);
|
|
29194
|
-
|
|
29390
|
+
const overriding = overridingSubsystemIds(root);
|
|
29391
|
+
const view = {
|
|
29392
|
+
projectType: application.profileId,
|
|
29393
|
+
locked,
|
|
29394
|
+
profileSource: application.source,
|
|
29395
|
+
// The write path guarantees resolvability — the ensure seam refused anything else.
|
|
29396
|
+
profileResolvable: true,
|
|
29397
|
+
unappliedProfileIds: remainder,
|
|
29398
|
+
overridingSubsystemIds: overriding
|
|
29399
|
+
};
|
|
29400
|
+
if (application.adoptedPackName) view.adoptedPackName = application.adoptedPackName;
|
|
29401
|
+
return view;
|
|
29195
29402
|
}
|
|
29196
29403
|
function getPackPolicy(cfg, credential) {
|
|
29197
29404
|
requirePrincipal4(cfg, credential);
|
|
@@ -32185,6 +32392,9 @@ function getProjectConfig2(cfg, credential, projectId) {
|
|
|
32185
32392
|
function setProjectType2(cfg, credential, projectId, projectType) {
|
|
32186
32393
|
return setProjectType(cfg, credential, projectId, projectType);
|
|
32187
32394
|
}
|
|
32395
|
+
function listProjectProfiles2(cfg, credential, project2) {
|
|
32396
|
+
return listProjectProfiles(cfg, credential, project2);
|
|
32397
|
+
}
|
|
32188
32398
|
function listProducers2(cfg, credential, project2) {
|
|
32189
32399
|
return listProducers(cfg, credential, project2);
|
|
32190
32400
|
}
|
|
@@ -35546,6 +35756,9 @@ function opsGetProjectConfig(cfg, sessionId, url, res) {
|
|
|
35546
35756
|
function opsSetProjectConfig(cfg, sessionId, body, res) {
|
|
35547
35757
|
sendJson(res, 200, setProjectType2(cfg, sessionId, String(body?.projectId ?? ""), String(body?.projectType ?? "")));
|
|
35548
35758
|
}
|
|
35759
|
+
function opsListProjectProfiles(cfg, sessionId, url, res) {
|
|
35760
|
+
sendJson(res, 200, { profiles: listProjectProfiles2(cfg, sessionId, q(url, "projectId") ?? "") });
|
|
35761
|
+
}
|
|
35549
35762
|
function opsListProducers(cfg, sessionId, url, res) {
|
|
35550
35763
|
sendJson(res, 200, { producers: listProducers2(cfg, sessionId, q(url, "projectId") ?? "") });
|
|
35551
35764
|
}
|
|
@@ -35785,6 +35998,9 @@ async function handleWebRequest(cfg, req, res, body, url, ctx) {
|
|
|
35785
35998
|
if (req.method === "POST" && parts.length === 3 && parts[2] === "config") {
|
|
35786
35999
|
return opsSetProjectConfig(cfg, sessionId, body, res);
|
|
35787
36000
|
}
|
|
36001
|
+
if (req.method === "GET" && parts.length === 3 && parts[2] === "profiles") {
|
|
36002
|
+
return opsListProjectProfiles(cfg, sessionId, url, res);
|
|
36003
|
+
}
|
|
35788
36004
|
if (req.method === "GET" && parts.length === 3 && parts[2] === "policy") {
|
|
35789
36005
|
return opsPolicyEvaluate(cfg, sessionId, url, res);
|
|
35790
36006
|
}
|