Classify tenant apply policy actions
Refine tenant-apply planning so future automatic candidates, manual-only steps, and permanent out-of-scope actions are reported explicitly instead of being implied by generic prose. --- Build: pass | Tests: pass — 31 passed (1 file)
This commit is contained in:
parent
0f81c69d28
commit
253cdcecb6
5 changed files with 111 additions and 0 deletions
|
|
@ -282,6 +282,16 @@ Any future live `tenant-apply` must satisfy these rules:
|
|||
- require explicit operator review before host mutation
|
||||
- keep per-tenant hostd, Unix users, and repo workspaces out of scope
|
||||
|
||||
The intended policy buckets are:
|
||||
|
||||
- future automatic candidates:
|
||||
tenant-owned databases, tenant-owned worker jails, tenant-owned datasets
|
||||
- manual-only:
|
||||
operator approval and any host-level execution step
|
||||
- out of scope:
|
||||
per-tenant hostd, per-tenant Unix users, per-tenant repo workspaces, any
|
||||
shared platform resource mutation
|
||||
|
||||
Preflight for a future live apply should at minimum verify:
|
||||
|
||||
- tenant exists in the registry
|
||||
|
|
|
|||
|
|
@ -200,6 +200,8 @@ Also updated:
|
|||
- what remains manual or explicitly out of scope
|
||||
- a structured preflight checklist showing what already passes in the
|
||||
declarative model and what still blocks any automatic apply
|
||||
- explicit policy buckets for future automatic candidates, manual-only
|
||||
steps, and permanent out-of-scope actions
|
||||
|
||||
## Recommended first code tasks
|
||||
|
||||
|
|
|
|||
|
|
@ -167,6 +167,17 @@ function printApplyPlan(
|
|||
console.log(`Allowed databases: ${plan.allowedResources.databases.join(', ')}`);
|
||||
console.log(`Allowed worker jails: ${plan.allowedResources.workerJails.join(', ')}`);
|
||||
console.log(`Allowed datasets: ${plan.allowedResources.datasets.join(', ') || '(none)'}`);
|
||||
console.log('Action policy:');
|
||||
for (const action of plan.actionPolicy.automaticCandidates) {
|
||||
console.log(`- [future-auto] ${action.name}: ${action.resources.join(', ') || '(none)'}`);
|
||||
console.log(` ${action.detail}`);
|
||||
}
|
||||
for (const action of plan.actionPolicy.manualOnly) {
|
||||
console.log(`- [manual] ${action.name}: ${action.detail}`);
|
||||
}
|
||||
for (const action of plan.actionPolicy.outOfScope) {
|
||||
console.log(`- [out-of-scope] ${action.name}: ${action.detail}`);
|
||||
}
|
||||
if (plan.blockers.length > 0) {
|
||||
console.log('Blockers:');
|
||||
for (const blocker of plan.blockers) {
|
||||
|
|
|
|||
|
|
@ -97,6 +97,24 @@ describe('tenant-registry', () => {
|
|||
}),
|
||||
]),
|
||||
);
|
||||
expect(plan.actionPolicy.automaticCandidates).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: 'Tenant databases',
|
||||
resources: expect.arrayContaining(['mevy_brain']),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
name: 'Tenant worker jails',
|
||||
resources: expect.arrayContaining(['mevy_ctrl_worker']),
|
||||
}),
|
||||
]),
|
||||
);
|
||||
expect(plan.actionPolicy.outOfScope).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ name: 'Per-tenant hostd' }),
|
||||
expect.objectContaining({ name: 'Shared platform resources' }),
|
||||
]),
|
||||
);
|
||||
expect(plan.manualSteps).toContain(
|
||||
'No live resources are created by this workflow today.',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -139,6 +139,21 @@ export interface TenantApplyPlan {
|
|||
tenant: TenantRecord;
|
||||
registryPath: string;
|
||||
readyForAutomaticApply: boolean;
|
||||
actionPolicy: {
|
||||
automaticCandidates: Array<{
|
||||
name: string;
|
||||
resources: string[];
|
||||
detail: string;
|
||||
}>;
|
||||
manualOnly: Array<{
|
||||
name: string;
|
||||
detail: string;
|
||||
}>;
|
||||
outOfScope: Array<{
|
||||
name: string;
|
||||
detail: string;
|
||||
}>;
|
||||
};
|
||||
allowedResources: {
|
||||
databases: string[];
|
||||
workerJails: string[];
|
||||
|
|
@ -682,6 +697,61 @@ export function planTenantApply(
|
|||
tenant,
|
||||
registryPath,
|
||||
readyForAutomaticApply: false,
|
||||
actionPolicy: {
|
||||
automaticCandidates: [
|
||||
{
|
||||
name: 'Tenant databases',
|
||||
resources: Object.values(tenant.databases),
|
||||
detail:
|
||||
'A future live apply may create tenant-owned databases only, with no shared DB mutation.',
|
||||
},
|
||||
{
|
||||
name: 'Tenant worker jails',
|
||||
resources: tenant.workerJails,
|
||||
detail:
|
||||
'A future live apply may provision tenant-owned worker jails only, subject to host-level review.',
|
||||
},
|
||||
{
|
||||
name: 'Tenant datasets',
|
||||
resources: tenant.datasets,
|
||||
detail:
|
||||
'A future live apply may create tenant-owned datasets only, without touching shared platform datasets.',
|
||||
},
|
||||
],
|
||||
manualOnly: [
|
||||
{
|
||||
name: 'Operator approval',
|
||||
detail:
|
||||
'Any future live apply must require explicit operator confirmation before host mutation.',
|
||||
},
|
||||
{
|
||||
name: 'Host-level execution',
|
||||
detail:
|
||||
'Any future jail, dataset, or database creation must run as an explicit host-level step.',
|
||||
},
|
||||
],
|
||||
outOfScope: [
|
||||
{
|
||||
name: 'Per-tenant hostd',
|
||||
detail: 'Tenant apply must never create a separate hostd service.',
|
||||
},
|
||||
{
|
||||
name: 'Per-tenant Unix user',
|
||||
detail:
|
||||
'Tenant apply must not create a tenant-scoped Unix user or home contract.',
|
||||
},
|
||||
{
|
||||
name: 'Per-tenant repo workspace',
|
||||
detail:
|
||||
'Tenant apply must not create a tenant-specific repo checkout or runtime workspace.',
|
||||
},
|
||||
{
|
||||
name: 'Shared platform resources',
|
||||
detail:
|
||||
'Tenant apply must never create, mutate, or delete shared platform services, datasets, or jails.',
|
||||
},
|
||||
],
|
||||
},
|
||||
allowedResources: {
|
||||
databases: Object.values(tenant.databases),
|
||||
workerJails: tenant.workerJails,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue