diff --git a/.repository-projection.json b/.repository-projection.json index 0c65c52..ae2fe1c 100644 --- a/.repository-projection.json +++ b/.repository-projection.json @@ -3,11 +3,11 @@ "projection": "api", "projectionSchemaVersion": 1, "sourceRepository": "dx-corp/mono", - "sourceSha": "916d407917e806df56819c92b7ebc8c9cdcef9b5", + "sourceSha": "c27319825e1c40e34be35016e71b4553c4313dc0", "destinationRepository": "dx-corp/api", - "priorProjectedBase": "66644245a4ed1a2a9c95f4429fb9f7c4d950db9f", + "priorProjectedBase": "9b8d355e944a1d6210a236180ee66487d65406c1", "definitionDigest": "144b18a5c1f3e7ee6e2d1abc32f80a97adfeacd088911ec659d63622fe85d18c", "toolDigest": "898e8657d9153a2a51d7c283bf83bb3350b5d1e6", - "contentDigest": "a108858b354bdde6927ace26afefc67ae670a18ca08fc8e762e19830b6c842fe", + "contentDigest": "a9ccfd1e655995ca89d08ca2597ee4720c5e6b0d0ee4b6341c8efb0bc07ebc9d", "publicationEligible": true } diff --git a/openapi/platform/v1/platform.openapi.yaml b/openapi/platform/v1/platform.openapi.yaml index bc52895..ace3453 100644 --- a/openapi/platform/v1/platform.openapi.yaml +++ b/openapi/platform/v1/platform.openapi.yaml @@ -479,6 +479,22 @@ components: - WORK_KIND_EVAL_RUN - WORK_KIND_COMPUTER_MISSION - WORK_KIND_ARTIFACT_RENDER + platform.v1.WorkRemediationClassification: + type: string + title: WorkRemediationClassification + enum: + - WORK_REMEDIATION_CLASSIFICATION_UNSPECIFIED + - WORK_REMEDIATION_CLASSIFICATION_AUTO_EXECUTABLE + - WORK_REMEDIATION_CLASSIFICATION_APPROVAL_EXECUTABLE + - WORK_REMEDIATION_CLASSIFICATION_MANUAL_WORK + - WORK_REMEDIATION_CLASSIFICATION_BLOCKED + platform.v1.WorkRemediationEvidenceIndependence: + type: string + title: WorkRemediationEvidenceIndependence + enum: + - WORK_REMEDIATION_EVIDENCE_INDEPENDENCE_UNSPECIFIED + - WORK_REMEDIATION_EVIDENCE_INDEPENDENCE_ACTION_OUTPUT + - WORK_REMEDIATION_EVIDENCE_INDEPENDENCE_INDEPENDENT_OBSERVATION platform.v1.WorkState: type: string title: WorkState @@ -1139,6 +1155,10 @@ components: evalAssignment: title: eval_assignment $ref: '#/components/schemas/platform.v1.EvalAssignment' + remediationPlan: + title: remediation_plan + description: Immutable, versioned remediation plan owned by this Work item. + $ref: '#/components/schemas/platform.v1.WorkRemediationPlan' title: NewWorkItem additionalProperties: false platform.v1.OperationContext: @@ -1843,11 +1863,188 @@ components: evalAssignment: title: eval_assignment $ref: '#/components/schemas/platform.v1.EvalAssignment' + remediationPlan: + title: remediation_plan + $ref: '#/components/schemas/platform.v1.WorkRemediationPlan' title: WorkItem required: - scope - createdBy additionalProperties: false + platform.v1.WorkRemediationAction: + type: object + properties: + actionId: + type: string + title: action_id + minLength: 1 + catalogDigest: + type: string + title: catalog_digest + minLength: 1 + inputDigest: + type: string + title: input_digest + minLength: 1 + target: + title: target + $ref: '#/components/schemas/platform.v1.WorkRemediationResource' + riskTier: + not: + enum: + - 0 + title: risk_tier + $ref: '#/components/schemas/platform.v1.RiskTier' + approvalRequired: + type: boolean + title: approval_required + requiredScopes: + type: array + items: + type: string + title: required_scopes + idempotencyKey: + type: string + title: idempotency_key + minLength: 1 + postconditionIds: + type: array + items: + type: string + title: postcondition_ids + inputArtifactRef: + title: input_artifact_ref + description: |- + Immutable ArtifactVersion containing schema-validated provider arguments. + input_digest binds its exact bytes; secrets remain references. + $ref: '#/components/schemas/platform.v1.ResourceRef' + title: WorkRemediationAction + required: + - target + - inputArtifactRef + additionalProperties: false + platform.v1.WorkRemediationPlan: + type: object + properties: + schemaVersion: + exclusiveMinimum: 0 + type: integer + title: schema_version + planDigest: + type: string + title: plan_digest + minLength: 1 + scope: + title: scope + $ref: '#/components/schemas/platform.v1.TenantScope' + sourceFindingId: + type: string + title: source_finding_id + minLength: 1 + sourceEvidence: + type: array + items: + $ref: '#/components/schemas/platform.v1.RecordRef' + title: source_evidence + affectedResources: + type: array + items: + $ref: '#/components/schemas/platform.v1.WorkRemediationResource' + title: affected_resources + postconditions: + type: array + items: + $ref: '#/components/schemas/platform.v1.WorkRemediationPostcondition' + title: postconditions + actions: + type: array + items: + $ref: '#/components/schemas/platform.v1.WorkRemediationAction' + title: actions + classification: + not: + enum: + - 0 + title: classification + $ref: '#/components/schemas/platform.v1.WorkRemediationClassification' + lineageId: + type: string + title: lineage_id + minLength: 1 + idempotencyKey: + type: string + title: idempotency_key + minLength: 1 + nonExecutableReason: + type: string + title: non_executable_reason + description: |- + Manual and blocked Work retain an explicit reason rather than inventing + an executable connector action. + title: WorkRemediationPlan + required: + - scope + additionalProperties: false + description: |- + A typed extension of Platform Work, not a separate execution or approval + owner. plan_digest excludes itself and binds every immutable field below. + platform.v1.WorkRemediationPostcondition: + type: object + properties: + postconditionId: + type: string + title: postcondition_id + minLength: 1 + target: + title: target + $ref: '#/components/schemas/platform.v1.WorkRemediationResource' + observerActionId: + type: string + title: observer_action_id + minLength: 1 + expectedStateDigest: + type: string + title: expected_state_digest + minLength: 1 + maxAgeSeconds: + exclusiveMinimum: 0 + type: integer + title: max_age_seconds + requiredIndependence: + not: + enum: + - 0 + title: required_independence + $ref: '#/components/schemas/platform.v1.WorkRemediationEvidenceIndependence' + title: WorkRemediationPostcondition + required: + - target + additionalProperties: false + platform.v1.WorkRemediationResource: + type: object + properties: + providerId: + type: string + title: provider_id + minLength: 1 + connectionId: + type: string + title: connection_id + minLength: 1 + stableResourceId: + type: string + title: stable_resource_id + minLength: 1 + resourceKind: + type: string + title: resource_kind + minLength: 1 + platformResource: + title: platform_resource + $ref: '#/components/schemas/platform.v1.ResourceRef' + title: WorkRemediationResource + additionalProperties: false + description: Exact external identity; the enclosing Work scope remains tenant authority. connect-protocol-version: type: number title: Connect-Protocol-Version diff --git a/proto/platform/v1/platform.proto b/proto/platform/v1/platform.proto index 75eeb7b..1c3f077 100644 --- a/proto/platform/v1/platform.proto +++ b/proto/platform/v1/platform.proto @@ -204,6 +204,8 @@ message NewWorkItem { string parent_work_id = 3; google.protobuf.Struct metadata = 4; EvalAssignment eval_assignment = 5; + // Immutable, versioned remediation plan owned by this Work item. + WorkRemediationPlan remediation_plan = 6; } message WorkItem { @@ -217,6 +219,7 @@ message WorkItem { string lineage_id = 8 [(buf.validate.field).string.min_len = 1]; google.protobuf.Struct metadata = 9; EvalAssignment eval_assignment = 10; + WorkRemediationPlan remediation_plan = 11; } enum ResourceKind { @@ -253,6 +256,81 @@ message ResourceRef { int32 version = 4 [(buf.validate.field).int32.gte = 0]; } +enum WorkRemediationClassification { + WORK_REMEDIATION_CLASSIFICATION_UNSPECIFIED = 0; + WORK_REMEDIATION_CLASSIFICATION_AUTO_EXECUTABLE = 1; + WORK_REMEDIATION_CLASSIFICATION_APPROVAL_EXECUTABLE = 2; + WORK_REMEDIATION_CLASSIFICATION_MANUAL_WORK = 3; + WORK_REMEDIATION_CLASSIFICATION_BLOCKED = 4; +} + +enum WorkRemediationEvidenceIndependence { + WORK_REMEDIATION_EVIDENCE_INDEPENDENCE_UNSPECIFIED = 0; + WORK_REMEDIATION_EVIDENCE_INDEPENDENCE_ACTION_OUTPUT = 1; + WORK_REMEDIATION_EVIDENCE_INDEPENDENCE_INDEPENDENT_OBSERVATION = 2; +} + +// Exact external identity; the enclosing Work scope remains tenant authority. +message WorkRemediationResource { + string provider_id = 1 [(buf.validate.field).string.min_len = 1]; + string connection_id = 2 [(buf.validate.field).string.min_len = 1]; + string stable_resource_id = 3 [(buf.validate.field).string.min_len = 1]; + string resource_kind = 4 [(buf.validate.field).string.min_len = 1]; + ResourceRef platform_resource = 5; +} + +message WorkRemediationAction { + string action_id = 1 [(buf.validate.field).string.min_len = 1]; + string catalog_digest = 2 [(buf.validate.field).string.min_len = 1]; + string input_digest = 3 [(buf.validate.field).string.min_len = 1]; + WorkRemediationResource target = 4 [(buf.validate.field).required = true]; + RiskTier risk_tier = 5 [(buf.validate.field).enum = { + defined_only: true + not_in: [0] + }]; + bool approval_required = 6; + repeated string required_scopes = 7; + string idempotency_key = 8 [(buf.validate.field).string.min_len = 1]; + repeated string postcondition_ids = 9; + // Immutable ArtifactVersion containing schema-validated provider arguments. + // input_digest binds its exact bytes; secrets remain references. + ResourceRef input_artifact_ref = 10 [(buf.validate.field).required = true]; +} + +message WorkRemediationPostcondition { + string postcondition_id = 1 [(buf.validate.field).string.min_len = 1]; + WorkRemediationResource target = 2 [(buf.validate.field).required = true]; + string observer_action_id = 3 [(buf.validate.field).string.min_len = 1]; + string expected_state_digest = 4 [(buf.validate.field).string.min_len = 1]; + uint32 max_age_seconds = 5 [(buf.validate.field).uint32.gt = 0]; + WorkRemediationEvidenceIndependence required_independence = 6 [(buf.validate.field).enum = { + defined_only: true + not_in: [0] + }]; +} + +// A typed extension of Platform Work, not a separate execution or approval +// owner. plan_digest excludes itself and binds every immutable field below. +message WorkRemediationPlan { + uint32 schema_version = 1 [(buf.validate.field).uint32.gt = 0]; + string plan_digest = 2 [(buf.validate.field).string.min_len = 1]; + TenantScope scope = 3 [(buf.validate.field).required = true]; + string source_finding_id = 4 [(buf.validate.field).string.min_len = 1]; + repeated RecordRef source_evidence = 5; + repeated WorkRemediationResource affected_resources = 6; + repeated WorkRemediationPostcondition postconditions = 7; + repeated WorkRemediationAction actions = 8; + WorkRemediationClassification classification = 9 [(buf.validate.field).enum = { + defined_only: true + not_in: [0] + }]; + string lineage_id = 10 [(buf.validate.field).string.min_len = 1]; + string idempotency_key = 11 [(buf.validate.field).string.min_len = 1]; + // Manual and blocked Work retain an explicit reason rather than inventing + // an executable connector action. + string non_executable_reason = 12; +} + // RecordKind identifies an authoritative operational record without copying // that record into a read model. The enclosing request supplies exact tenant // authority; the kind selects the owner resolver for record_id.