ci/woodpecker/push/publish Pipeline was successful
Co-authored-by: fred <[email protected]>
108 lines
3.0 KiB
TypeScript
108 lines
3.0 KiB
TypeScript
import { Type } from 'class-transformer';
|
|
import {
|
|
IsIn,
|
|
IsOptional,
|
|
IsString,
|
|
IsUUID,
|
|
MaxLength,
|
|
MinLength,
|
|
ValidateIf,
|
|
ValidateNested,
|
|
} from 'class-validator';
|
|
|
|
/**
|
|
* Agent enrollment command DTOs (design
|
|
* docs/plans/2026-08-29-agent-enrollment-command-design.md §3.1/§3.2,
|
|
* contract 5 §4.1 typed boundary).
|
|
*
|
|
* The global ValidationPipe runs with whitelist + forbidNonWhitelisted, so
|
|
* closure is contract surface here exactly as in the hierarchy DTOs:
|
|
* - EnrollAgentDto declares NO isSystem field — `is_system` is never
|
|
* settable through this command (design §3.1 rule 4); the pipe refuses it.
|
|
* - replayMode admits ONLY 'actor-bound': `shared` is seed-only (contract 3
|
|
* §4.3), so a shared declaration is refused `validation_failed` at the
|
|
* boundary, executes nothing, and records no fence row (design §3.1).
|
|
* Every class here must be registered in PIPE_GUARDED_DTOS so the boot-time
|
|
* assertion proves the pipe sees the decorators.
|
|
*/
|
|
|
|
/**
|
|
* Credential input, discriminated on `mode` (design §3.1):
|
|
* - `{ mode: 'reference' }` — a stored credential for (actor, provider)
|
|
* must already exist; `type`/`value` must be ABSENT (the repository
|
|
* refuses a reference that smuggles a value).
|
|
* - `{ mode: 'intake', type: 'api_key', value }` — the value is sealed
|
|
* into the credential store inside the enrollment transaction and is
|
|
* never echoed anywhere (§3.1 rule 1).
|
|
*/
|
|
export class EnrollCredentialDto {
|
|
@IsIn(['reference', 'intake'])
|
|
mode!: 'reference' | 'intake';
|
|
|
|
@ValidateIf((o: EnrollCredentialDto) => o.mode === 'intake')
|
|
@IsIn(['api_key'])
|
|
type?: 'api_key';
|
|
|
|
@ValidateIf((o: EnrollCredentialDto) => o.mode === 'intake')
|
|
@IsString()
|
|
@MinLength(1)
|
|
@MaxLength(4096)
|
|
value?: string;
|
|
}
|
|
|
|
export class EnrollAgentDto {
|
|
/** Registered harness name; a well-formed name missing from the registry is `precondition_failed`. */
|
|
@IsString()
|
|
@MinLength(1)
|
|
@MaxLength(200)
|
|
harness!: string;
|
|
|
|
@IsString()
|
|
@MinLength(1)
|
|
@MaxLength(200)
|
|
name!: string;
|
|
|
|
/** Stored as the agent's system prompt; null/absent leaves it unset. */
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(20000)
|
|
persona?: string | null;
|
|
|
|
/** Provider-qualified model id. */
|
|
@IsString()
|
|
@MinLength(1)
|
|
@MaxLength(200)
|
|
model!: string;
|
|
|
|
/** Names the credential's provider. */
|
|
@IsString()
|
|
@MinLength(1)
|
|
@MaxLength(200)
|
|
provider!: string;
|
|
|
|
@ValidateNested()
|
|
@Type(() => EnrollCredentialDto)
|
|
credential!: EnrollCredentialDto;
|
|
|
|
/** REQUIRED — contract 3 §4.3, ratified into contract 5 §4 via §7 item 4. */
|
|
@IsUUID()
|
|
idempotencyKey!: string;
|
|
|
|
/** Optional; generated when absent (contract 5 §4.3). */
|
|
@IsOptional()
|
|
@IsUUID()
|
|
correlationId?: string;
|
|
|
|
/** Only 'actor-bound' is admissible on this family — see module doc. */
|
|
@IsOptional()
|
|
@IsIn(['actor-bound'])
|
|
replayMode?: 'actor-bound';
|
|
}
|
|
|
|
/** Query envelope for agent.enrollment.get (design §3.2): correlation only, no idempotency key. */
|
|
export class GetEnrollmentQueryDto {
|
|
@IsOptional()
|
|
@IsUUID()
|
|
correlationId?: string;
|
|
}
|