live compose output during deploys, plus a per-stack deploy history tab
This commit is contained in:
41 files changed
+2093
-1159
No files matched your search
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Pure permission mapping for reading schedule_executions rows. No imports, so
|
||||
* it stays unit-testable without the DB/auth module chain.
|
||||
*
|
||||
* A schedule execution's row (its errorMessage, details, and full logs) is only
|
||||
* as sensitive as the thing it ran, so reading it is gated by the SAME resource
|
||||
* permission that gates the underlying feature -- NOT a single blanket
|
||||
* 'schedules:view'. That would either over-restrict (a backups-only viewer
|
||||
* loses backup run stats) or under-restrict (a schedules-only viewer reads
|
||||
* compose stderr from a stack deploy they can't otherwise see). Deploy stderr
|
||||
* can carry redacted-but-not-guaranteed-clean output, hence the care.
|
||||
*/
|
||||
|
||||
export type ScheduleExecResource = 'stacks' | 'backups' | 'schedules';
|
||||
|
||||
/** Every schedule type that maps to a NON-generic resource. Types not listed here
|
||||
* fall through to 'schedules' in resourceForScheduleType. Kept here (not inlined)
|
||||
* so the list gate can enumerate which types a resource-scoped caller may see. */
|
||||
const NON_GENERIC_TYPES: Record<string, ScheduleExecResource> = {
|
||||
stack_deploy: 'stacks',
|
||||
git_stack_sync: 'stacks',
|
||||
backup: 'backups',
|
||||
restore: 'backups'
|
||||
};
|
||||
|
||||
/**
|
||||
* The resource whose `:view` permission a caller must hold to read executions of
|
||||
* this schedule type. Unknown/unrecognized types fall back to 'schedules' -- the
|
||||
* generic bucket, never a weaker one.
|
||||
*/
|
||||
export function resourceForScheduleType(scheduleType: string): ScheduleExecResource {
|
||||
return NON_GENERIC_TYPES[scheduleType] ?? 'schedules';
|
||||
}
|
||||
|
||||
/**
|
||||
* The concrete schedule types whose executions a caller may read given which
|
||||
* resource :view permissions they hold. Used to bound a NO-scheduleType-filter
|
||||
* list query so a caller never receives errorMessage/details of a type they lack
|
||||
* permission for.
|
||||
*
|
||||
* Returns null when 'schedules' AND 'stacks' AND 'backups' are all viewable --
|
||||
* i.e. every type is allowed, so no type filter is needed (null = "do not
|
||||
* filter", matching getScheduleExecutions' scheduleTypes semantics). Otherwise
|
||||
* returns the explicit allow-list: the always-generic types when 'schedules' is
|
||||
* held, plus each NON_GENERIC type whose resource is held.
|
||||
*
|
||||
* `allKnownTypes` is passed in (the caller has the ScheduleType union) so this
|
||||
* stays dependency-free and testable.
|
||||
*/
|
||||
export function viewableScheduleTypes(
|
||||
viewable: { schedules: boolean; stacks: boolean; backups: boolean },
|
||||
allKnownTypes: readonly string[]
|
||||
): string[] | null {
|
||||
if (viewable.schedules && viewable.stacks && viewable.backups) return null;
|
||||
const allowed: string[] = [];
|
||||
for (const t of allKnownTypes) {
|
||||
const resource = resourceForScheduleType(t);
|
||||
if (viewable[resource]) allowed.push(t);
|
||||
}
|
||||
return allowed;
|
||||
}
|
||||
Reference in new issue
Block a user