thinkwork-cli 0.12.11 → 0.12.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/README.md +42 -38
- package/dist/{api-client-ASJWIG3Z.js → api-client-4VT3FWOH.js} +1 -1
- package/dist/{chunk-JEHV35EU.js → chunk-H7AB42ES.js} +340 -30
- package/dist/cli.js +22157 -9229
- package/dist/commands/enterprise/templates/deploy-repo/.github/workflows/deploy.yml +17 -6
- package/dist/commands/enterprise/templates/deploy-repo/docs/runbook.md +81 -9
- package/dist/commands/enterprise/templates/deploy-repo/scripts/apply-release.mjs +183 -21
- package/dist/commands/enterprise/templates/deploy-repo/scripts/smoke.mjs +1 -2
- package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +286 -0
- package/dist/drizzle/0000_petite_marvel_apes.sql +1188 -0
- package/dist/drizzle/0001_milky_surge.sql +103 -0
- package/dist/drizzle/0002_aberrant_mattie_franklin.sql +41 -0
- package/dist/drizzle/0003_exotic_ogun.sql +3 -0
- package/dist/drizzle/0004_glamorous_magneto.sql +2 -0
- package/dist/drizzle/0005_ancient_nocturne.sql +2 -0
- package/dist/drizzle/0006_new_colonel_america.sql +2 -0
- package/dist/drizzle/0007_unique_external_task_id.sql +31 -0
- package/dist/drizzle/0008_external_task_id_column.sql +43 -0
- package/dist/drizzle/0009_evaluations.sql +64 -0
- package/dist/drizzle/0010_eval_agent_template.sql +2 -0
- package/dist/drizzle/0011_eval_run_template.sql +2 -0
- package/dist/drizzle/0012_eval_seed_unique.sql +16 -0
- package/dist/drizzle/0013_motionless_white_queen.sql +140 -0
- package/dist/drizzle/0014_wiki_aggregation.sql +11 -0
- package/dist/drizzle/0015_pg_trgm_alias_title_indexes.sql +9 -0
- package/dist/drizzle/0016_wiki_schema_drops.sql +24 -0
- package/dist/drizzle/0017_wiki_places.sql +46 -0
- package/dist/drizzle/0018_agent_workspace_overlay.sql +26 -0
- package/dist/drizzle/0018_cool_firebird.sql +24 -0
- package/dist/drizzle/0018_skill_runs.sql +84 -0
- package/dist/drizzle/0019_condemned_dragon_man.sql +95 -0
- package/dist/drizzle/0019_webhook_skill_runs.sql +58 -0
- package/dist/drizzle/0020_crazy_the_anarchist.sql +9 -0
- package/dist/drizzle/0020_mutation_idempotency.sql +64 -0
- package/dist/drizzle/0021_crm_work_links.sql +76 -0
- package/dist/drizzle/0021_skill_runs_completion_hmac.sql +33 -0
- package/dist/drizzle/0022_add_billing_tables.sql +70 -0
- package/dist/drizzle/0022_seed_thinkwork_admin_permissions.sql +160 -0
- package/dist/drizzle/0022_stripe_billing_indexes.sql +48 -0
- package/dist/drizzle/0023_tenants_deactivation.sql +27 -0
- package/dist/drizzle/0024_tenant_mcp_admin_keys.sql +63 -0
- package/dist/drizzle/0025_v1_agent_architecture.sql +182 -0
- package/dist/drizzle/0026_thread_turns_add_kind.sql +28 -0
- package/dist/drizzle/0027_capability_catalog_and_manifests.sql +219 -0
- package/dist/drizzle/0028_aws_s3_extension.sql +26 -0
- package/dist/drizzle/0029_collapse_execution_types.sql +42 -0
- package/dist/drizzle/0030_retire_composition_primitives.sql +48 -0
- package/dist/drizzle/0031_thread_cleanup_drops.sql +131 -0
- package/dist/drizzle/0032_add_browser_automation_template_config.sql +24 -0
- package/dist/drizzle/0033_agent_operation_leases.sql +32 -0
- package/dist/drizzle/0034_agent_workspace_events.sql +116 -0
- package/dist/drizzle/0035_workspace_review_decisions.sql +19 -0
- package/dist/drizzle/0036_user_scoped_memory_wiki.sql +152 -0
- package/dist/drizzle/0037_user_profile_operating_model.sql +34 -0
- package/dist/drizzle/0042_agent_runtime_selector.sql +41 -0
- package/dist/drizzle/0043_wiki_search_tsv_tokenization.sql +48 -0
- package/dist/drizzle/0044_add_web_search_template_config.sql +7 -0
- package/dist/drizzle/0045_add_send_email_template_config.sql +7 -0
- package/dist/drizzle/0046_tenant_mcp_context_tools.sql +26 -0
- package/dist/drizzle/0047_add_context_engine_template_config.sql +7 -0
- package/dist/drizzle/0048_tenant_context_provider_settings.sql +22 -0
- package/dist/drizzle/0050_brain_v0_entity_subtype.sql +29 -0
- package/dist/drizzle/0051_brain_v0_tenant_entity_pages.sql +170 -0
- package/dist/drizzle/0052_brain_v0_external_refs.sql +41 -0
- package/dist/drizzle/0053_brain_v0_unresolved_mentions_subtype.sql +48 -0
- package/dist/drizzle/0054_wiki_compile_jobs_input.sql +28 -0
- package/dist/drizzle/0055_routines_stepfunctions_substrate.sql +202 -0
- package/dist/drizzle/0056_routine_step_events_dedup_idx.sql +25 -0
- package/dist/drizzle/0057_archive_legacy_python_routines.sql +36 -0
- package/dist/drizzle/0058_routines_visibility_and_owning_agent.sql +61 -0
- package/dist/drizzle/0061_routine_execution_asl_version_id.sql +29 -0
- package/dist/drizzle/0062_migrate_pi_to_flue.sql +110 -0
- package/dist/drizzle/0063_threads_session_data.sql +23 -0
- package/dist/drizzle/0064_tenant_credentials.sql +65 -0
- package/dist/drizzle/0067_thinkwork_computers_phase_one.sql +174 -0
- package/dist/drizzle/0068_drop_system_workflows_and_activation.sql +115 -0
- package/dist/drizzle/0069_compliance_schema.sql +364 -0
- package/dist/drizzle/0070_compliance_aurora_roles.sql +171 -0
- package/dist/drizzle/0072_threads_computer_ownership.sql +24 -0
- package/dist/drizzle/0073_compliance_tenant_anchor_state.sql +105 -0
- package/dist/drizzle/0074_compliance_event_hash_index.sql +49 -0
- package/dist/drizzle/0075_scheduled_jobs_computer_ownership.sql +27 -0
- package/dist/drizzle/0076_scheduled_jobs_marco_backfill.sql +69 -0
- package/dist/drizzle/0077_computers_primary_agent_id.sql +38 -0
- package/dist/drizzle/0078_tenant_customize_catalog.sql +46 -0
- package/dist/drizzle/0079_seed_tenant_customize_catalog.sql +53 -0
- package/dist/drizzle/0081_routines_catalog_slug.sql +42 -0
- package/dist/drizzle/0082_messages_parts_jsonb.sql +52 -0
- package/dist/drizzle/0083_computer_runbooks.sql +103 -0
- package/dist/drizzle/0084_artifacts_favorited_at.sql +32 -0
- package/dist/drizzle/0085_seed_thinkwork_computer_default_template.sql +46 -0
- package/dist/drizzle/0086_update_default_template_models.sql +19 -0
- package/dist/drizzle/0087_retire_oss_connectors.sql +77 -0
- package/dist/drizzle/0088_compliance_event_types_finance_pilot.sql +37 -0
- package/dist/drizzle/0089_remove_maniflow_eval_seeds.sql +81 -0
- package/dist/drizzle/0089_wiki_schema_extraction.sql +315 -0
- package/dist/drizzle/0090_brain_schema_extraction.sql +274 -0
- package/dist/drizzle/0091_drop_wiki_brain_compat_views.sql +118 -0
- package/dist/drizzle/0092_finish_oss_connector_retirement.sql +97 -0
- package/dist/drizzle/0093_eval_runs_scheduled_job_id.sql +23 -0
- package/dist/drizzle/0094_slack_workspace_app.sql +140 -0
- package/dist/drizzle/0095_eval_runs_computer_id.sql +22 -0
- package/dist/drizzle/0096_true_redteam_eval_seed_cleanup.sql +67 -0
- package/dist/drizzle/0097_shared_computers.sql +191 -0
- package/dist/drizzle/0098_business_ontology.sql +587 -0
- package/dist/drizzle/0099_thread_idle_learning.sql +145 -0
- package/dist/drizzle/0100_ontology_gated_brain_dynamic_subtypes.sql +7 -0
- package/dist/drizzle/0101_ontology_gated_unresolved_mentions_dynamic_subtypes.sql +7 -0
- package/dist/drizzle/0102_wiki_brain_owner_repair.sql +87 -0
- package/dist/drizzle/0103_brain_section_source_trigger_repair.sql +75 -0
- package/dist/drizzle/0104_expand_seed_ontology_for_user_memory.sql +166 -0
- package/dist/drizzle/0105_spaces_domain.sql +349 -0
- package/dist/drizzle/0106_expand_seed_ontology_for_triples.sql +173 -0
- package/dist/drizzle/0106_space_threads_participants.sql +197 -0
- package/dist/drizzle/0107_linked_task_mirror.sql +245 -0
- package/dist/drizzle/0108_message_mentions.sql +95 -0
- package/dist/drizzle/0109_space_owned_threads.sql +217 -0
- package/dist/drizzle/0110_thread_participant_read_state.sql +21 -0
- package/dist/drizzle/0111_agents_tenant_name_unique.sql +38 -0
- package/dist/drizzle/0112_recast_spaces_as_contextual_workrooms.sql +138 -0
- package/dist/drizzle/0113_agents_own_runtime_fields.sql +48 -0
- package/dist/drizzle/0114_migrate_templates_to_agents_and_spaces.sql +361 -0
- package/dist/drizzle/0115_remove_computer_eval_template_dependencies.sql +69 -0
- package/dist/drizzle/0116_backfill_thread_participants_access.sql +126 -0
- package/dist/drizzle/0117_space_access_mode.sql +40 -0
- package/dist/drizzle/0118_normalize_tenant_member_principal_type.sql +41 -0
- package/dist/drizzle/0119_space_knowledge_bases.sql +126 -0
- package/dist/drizzle/0120_space_automations.sql +58 -0
- package/dist/drizzle/0121_drop_computer_runbooks.sql +26 -0
- package/dist/drizzle/0122_space_email_triggers.sql +24 -0
- package/dist/drizzle/0123_single_platform_agent_and_overrides.sql +58 -0
- package/dist/drizzle/0124_thread_turns_finalized_at.sql +17 -0
- package/dist/drizzle/0125_drop_space_agent_assignments.sql +42 -0
- package/dist/drizzle/0126_migrate_flue_to_pi.sql +42 -0
- package/dist/drizzle/0127_runtime_type_observability.sql +28 -0
- package/dist/drizzle/0128_drop_eval_test_cases_agent_id.sql +37 -0
- package/dist/drizzle/0129_drop_code_factory_tables.sql +43 -0
- package/dist/drizzle/0129_eval_results_system_prompt.sql +30 -0
- package/dist/drizzle/0130_drop_teams_and_team_id_columns.sql +54 -0
- package/dist/drizzle/0131_drop_skill_catalog_and_tenant_skills.sql +33 -0
- package/dist/drizzle/0132_drop_computer_tables.sql +31 -0
- package/dist/drizzle/0133_drop_seed_view_tombstones.sql +79 -0
- package/dist/drizzle/0133_thread_turns_system_prompt.sql +22 -0
- package/dist/drizzle/0134_drop_dead_agent_runtime_tables.sql +53 -0
- package/dist/drizzle/0135_native_checklist_linked_tasks.sql +48 -0
- package/dist/drizzle/0136_goal_ledger.sql +55 -0
- package/dist/drizzle/0136_space_email_trigger_status.sql +66 -0
- package/dist/drizzle/0137_thread_participant_pins.sql +25 -0
- package/dist/drizzle/0138_users_cognito_sub.sql +30 -0
- package/dist/drizzle/0139_mobile_turn_client_id.sql +23 -0
- package/dist/drizzle/0140_workspace_folder_names.sql +36 -0
- package/dist/drizzle/0141_eval_runs_desktop_pi_provenance.sql +31 -0
- package/dist/drizzle/0142_pi_only_agent_runtime.sql +61 -0
- package/dist/drizzle/0143_add_web_extract_builtin_config.sql +28 -0
- package/dist/drizzle/0144_skill_catalog_index.sql +40 -0
- package/dist/drizzle/0145_knowledge_graph_thread_ingest.sql +512 -0
- package/dist/drizzle/0146_knowledge_graph_source_scope.sql +413 -0
- package/dist/drizzle/0147_knowledge_graph_scope_trigger_qualification.sql +211 -0
- package/dist/drizzle/0148_user_cost_attribution.sql +171 -0
- package/dist/drizzle/0149_managed_mcp_servers.sql +64 -0
- package/dist/drizzle/0149_user_model_approvals.sql +89 -0
- package/dist/drizzle/0150_bootstrap_first_admin_claim.sql +11 -0
- package/dist/drizzle/0151_managed_deployments.sql +91 -0
- package/dist/drizzle/0152_agent_profiles.sql +81 -0
- package/dist/drizzle/0153_message_mentions_agent_profile.sql +9 -0
- package/dist/drizzle/0154_customer_deployment_sessions.sql +61 -0
- package/dist/drizzle/0155_tenant_model_catalog.sql +152 -0
- package/dist/drizzle/0156_bootstrap_credential_leases.sql +52 -0
- package/dist/drizzle/0157_knowledge_graph_observations_source.sql +79 -0
- package/dist/drizzle/0158_pending_user_questions.sql +80 -0
- package/dist/drizzle/0158_wiki_tenant_scope.sql +38 -0
- package/dist/drizzle/0159_agent_profiles_space_local.sql +49 -0
- package/dist/drizzle/0159_application_plugins.sql +193 -0
- package/dist/drizzle/0159_eval_scoring_version.sql +46 -0
- package/dist/drizzle/0160_compliance_event_types_plugins.sql +37 -0
- package/dist/drizzle/0160_eval_datasets.sql +75 -0
- package/dist/drizzle/0160_eval_results_thread_turn.sql +35 -0
- package/dist/drizzle/0161_eval_run_pinning.sql +54 -0
- package/dist/drizzle/0161_tenant_mcp_servers_plugin_source.sql +62 -0
- package/dist/drizzle/0162_eval_result_override.sql +49 -0
- package/dist/drizzle/0163_eval_replay_tool_allowlist.sql +50 -0
- package/dist/drizzle/0164_eval_replay_tool_override_mode.sql +52 -0
- package/dist/drizzle/0165_plugin_premium_entitlements.sql +153 -0
- package/dist/drizzle/0166_company_brain_substrate_contract.sql +386 -0
- package/dist/drizzle/0167_company_brain_artifact_manifest_runtime.sql +85 -0
- package/dist/drizzle/0168_eval_skill_gate.sql +44 -0
- package/dist/drizzle/0169_release_update_jobs.sql +67 -0
- package/dist/drizzle/0170_email_channel_plugin.sql +291 -0
- package/dist/drizzle/0171_linked_task_external_providers.sql +30 -0
- package/dist/drizzle/0172_email_channel_sendgrid_provider.sql +8 -0
- package/dist/drizzle/0173_auth_provider_resources.sql +83 -0
- package/dist/drizzle/0174_workos_auth_bridges.sql +37 -0
- package/dist/drizzle/0175_workos_auth_sessions.sql +38 -0
- package/dist/drizzle/0176_n8n_agent_step_runs.sql +107 -0
- package/dist/drizzle/0177_workflow_control_plane.sql +281 -0
- package/dist/drizzle/0178_workflow_backfill_existing_routines.sql +525 -0
- package/dist/drizzle/0179_tenant_goal_budget_settings.sql +21 -0
- package/dist/drizzle/0180_skill_drafts.sql +89 -0
- package/dist/drizzle/0181_skill_draft_publish_status.sql +21 -0
- package/dist/drizzle/0182_agent_loops.sql +260 -0
- package/dist/drizzle/0183_okf_artifact_manifests.sql +52 -0
- package/dist/drizzle/0184_skill_catalog_trust_cache.sql +35 -0
- package/dist/drizzle/0185_agent_loop_space.sql +16 -0
- package/dist/drizzle/0186_tenant_mcp_runtime_metadata.sql +10 -0
- package/dist/drizzle/0187_native_work_items.sql +220 -0
- package/dist/drizzle/0188_company_etl_plugin_rename.sql +99 -0
- package/dist/drizzle/0189_trace_cost_substrate.sql +247 -0
- package/dist/drizzle/0190_billing_export_reconciliation.sql +101 -0
- package/dist/drizzle/0191_open_engine_work_item_queue.sql +66 -0
- package/dist/drizzle/0192_work_item_labels.sql +44 -0
- package/dist/drizzle/0193_work_item_documents.sql +31 -0
- package/dist/drizzle/0194_memory_retain_attempts.sql +103 -0
- package/dist/drizzle/0194_work_item_comments.sql +35 -0
- package/dist/drizzle/0195_plugin_app_overlays.sql +45 -0
- package/dist/drizzle/0196_pi_extensions.sql +118 -0
- package/dist/drizzle/0197_eval_profiles.sql +150 -0
- package/dist/drizzle/0198_eval_runs_unstable.sql +27 -0
- package/dist/drizzle/0199_eval_runs_cost_partial.sql +27 -0
- package/dist/drizzle/meta/_journal.json +160 -0
- package/dist/plugins/README.md +162 -0
- package/dist/plugins/catalog/package.json +40 -0
- package/dist/plugins/catalog/scripts/build-catalog.ts +120 -0
- package/dist/plugins/catalog/scripts/generate-plugin-registry.ts +144 -0
- package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +86 -0
- package/dist/plugins/catalog/src/__tests__/catalog.test.ts +308 -0
- package/dist/plugins/catalog/src/__tests__/contracts.test.ts +861 -0
- package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +124 -0
- package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +120 -0
- package/dist/plugins/catalog/src/catalog.ts +434 -0
- package/dist/plugins/catalog/src/contracts.ts +1498 -0
- package/dist/plugins/catalog/src/index.ts +4 -0
- package/dist/plugins/catalog/src/plugin-package.ts +171 -0
- package/dist/plugins/catalog/src/registry/generated-first-party.ts +76 -0
- package/dist/plugins/catalog/src/registry/index.ts +1 -0
- package/dist/plugins/catalog/tsconfig.json +8 -0
- package/dist/plugins/company-brain/README.md +37 -0
- package/dist/plugins/company-brain/package.json +33 -0
- package/dist/plugins/company-brain/runtime/cognee/Dockerfile +11 -0
- package/dist/plugins/company-brain/smoke/cognee-managed-app-smoke.mjs +458 -0
- package/dist/plugins/company-brain/smoke/cognee-memory-cutover-smoke.mjs +539 -0
- package/dist/plugins/company-brain/smoke/company-brain-context-engine-smoke.mjs +312 -0
- package/dist/plugins/company-brain/smoke/company-brain-operations-smoke.mjs +449 -0
- package/dist/plugins/company-brain/smoke/company-brain-plugin-smoke.mjs +655 -0
- package/dist/plugins/company-brain/smoke/hindsight-memory-isolation-smoke.mjs +474 -0
- package/dist/plugins/company-brain/src/api/cognee-client.ts +896 -0
- package/dist/plugins/company-brain/src/api/cognee-cluster-identity.ts +49 -0
- package/dist/plugins/company-brain/src/api/cognee-memory-scope.ts +84 -0
- package/dist/plugins/company-brain/src/api/context-engine-provider.ts +888 -0
- package/dist/plugins/company-brain/src/api/migration.ts +665 -0
- package/dist/plugins/company-brain/src/deployment/cognee-managed-app.ts +396 -0
- package/dist/plugins/company-brain/src/index.ts +62 -0
- package/dist/plugins/company-brain/src/manifest.ts +112 -0
- package/dist/plugins/company-brain/terraform/cognee/README.md +263 -0
- package/dist/plugins/company-brain/terraform/cognee/main.tf +766 -0
- package/dist/plugins/company-brain/terraform/cognee/outputs.tf +144 -0
- package/dist/plugins/company-brain/terraform/cognee/variables.tf +402 -0
- package/dist/plugins/company-brain/test/api/cognee-client.test.ts +562 -0
- package/dist/plugins/company-brain/test/api/cognee-memory-scope.test.ts +74 -0
- package/dist/plugins/company-brain/test/api/context-engine-provider.test.ts +447 -0
- package/dist/plugins/company-brain/test/api/migration.test.ts +465 -0
- package/dist/plugins/company-brain/test/manifest.test.ts +95 -0
- package/dist/plugins/company-brain/tsconfig.json +8 -0
- package/dist/plugins/company-data/README.md +49 -0
- package/dist/plugins/company-data/package.json +21 -0
- package/dist/plugins/company-data/src/index.ts +30 -0
- package/dist/plugins/company-data/src/manifest.ts +26 -0
- package/dist/plugins/company-data/test/manifest.test.ts +116 -0
- package/dist/plugins/company-data/tsconfig.json +8 -0
- package/dist/plugins/company-etl/README.md +46 -0
- package/dist/plugins/company-etl/package.json +21 -0
- package/dist/plugins/company-etl/src/index.ts +29 -0
- package/dist/plugins/company-etl/src/manifest.ts +26 -0
- package/dist/plugins/company-etl/test/manifest.test.ts +108 -0
- package/dist/plugins/company-etl/tsconfig.json +8 -0
- package/dist/plugins/email-channel/README.md +41 -0
- package/dist/plugins/email-channel/package.json +22 -0
- package/dist/plugins/email-channel/src/index.ts +36 -0
- package/dist/plugins/email-channel/src/manifest.ts +44 -0
- package/dist/plugins/email-channel/src/provider-contract.ts +36 -0
- package/dist/plugins/email-channel/test/manifest.test.ts +119 -0
- package/dist/plugins/email-channel/tsconfig.json +8 -0
- package/dist/plugins/lastmile/README.md +50 -0
- package/dist/plugins/lastmile/package.json +23 -0
- package/dist/plugins/lastmile/smoke/lastmile-plugin-smoke.mjs +661 -0
- package/dist/plugins/lastmile/src/api/tasks-adapter.ts +572 -0
- package/dist/plugins/lastmile/src/discovery.fixture.ts +64 -0
- package/dist/plugins/lastmile/src/index.ts +46 -0
- package/dist/plugins/lastmile/src/manifest.ts +139 -0
- package/dist/plugins/lastmile/test/api/tasks-adapter.test.ts +266 -0
- package/dist/plugins/lastmile/test/discovery.test.ts +88 -0
- package/dist/plugins/lastmile/tsconfig.json +8 -0
- package/dist/plugins/n8n/README.md +201 -0
- package/dist/plugins/n8n/n8n-app/README.md +33 -0
- package/dist/plugins/n8n/n8n-app/package.json +23 -0
- package/dist/plugins/n8n/n8n-app/src/application-config.ts +45 -0
- package/dist/plugins/n8n/n8n-app/src/front-components/thinkwork-workflows.front-component.tsx +970 -0
- package/dist/plugins/n8n/n8n-app/src/lib/n8n-app-data.ts +190 -0
- package/dist/plugins/n8n/n8n-app/src/vite-env.d.ts +7 -0
- package/dist/plugins/n8n/n8n-app/tsconfig.json +15 -0
- package/dist/plugins/n8n/package.json +35 -0
- package/dist/plugins/n8n/runtime/Dockerfile +18 -0
- package/dist/plugins/n8n/runtime/n8n-task-runners.json +14 -0
- package/dist/plugins/n8n/runtime/n8n-task-runners.json.template +14 -0
- package/dist/plugins/n8n/runtime/package-lock.json +13 -0
- package/dist/plugins/n8n/runtime/package.json +7 -0
- package/dist/plugins/n8n/scripts/sync-thinkwork-app.mjs +268 -0
- package/dist/plugins/n8n/smoke/README.md +95 -0
- package/dist/plugins/n8n/smoke/n8n-agent-step-bridge-smoke.mjs +866 -0
- package/dist/plugins/n8n/smoke/n8n-integrated-app-smoke.mjs +262 -0
- package/dist/plugins/n8n/smoke/n8n-managed-app-smoke.mjs +409 -0
- package/dist/plugins/n8n/smoke/n8n-mcp-smoke.mjs +624 -0
- package/dist/plugins/n8n/src/deployment/image-build.ts +172 -0
- package/dist/plugins/n8n/src/deployment/managed-app.ts +429 -0
- package/dist/plugins/n8n/src/index.ts +79 -0
- package/dist/plugins/n8n/src/manifest.ts +403 -0
- package/dist/plugins/n8n/src/package-config.ts +186 -0
- package/dist/plugins/n8n/src/skills/n8n-workflow-operator/SKILL.md +76 -0
- package/dist/plugins/n8n/src/skills/n8n-workflow-operator/references/mcp-tooling.md +40 -0
- package/dist/plugins/n8n/src/skills/n8n-workflow-operator/references/validation-and-handoff.md +40 -0
- package/dist/plugins/n8n/src/skills/n8n-workflow-operator/references/workflow-authoring.md +45 -0
- package/dist/plugins/n8n/terraform/n8n/README.md +113 -0
- package/dist/plugins/n8n/terraform/n8n/main.tf +918 -0
- package/dist/plugins/n8n/terraform/n8n/outputs.tf +124 -0
- package/dist/plugins/n8n/terraform/n8n/scripts/sync-database.py +250 -0
- package/dist/plugins/n8n/terraform/n8n/scripts/test_sync_database.py +55 -0
- package/dist/plugins/n8n/terraform/n8n/variables.tf +354 -0
- package/dist/plugins/n8n/test/image-build.test.ts +118 -0
- package/dist/plugins/n8n/test/integrated-app-contract.test.ts +353 -0
- package/dist/plugins/n8n/test/manifest.test.ts +278 -0
- package/dist/plugins/n8n/test/package-config.test.ts +57 -0
- package/dist/plugins/n8n/tsconfig.json +8 -0
- package/dist/plugins/sendgrid/README.md +30 -0
- package/dist/plugins/sendgrid/package.json +22 -0
- package/dist/plugins/sendgrid/src/index.ts +36 -0
- package/dist/plugins/sendgrid/src/manifest.ts +37 -0
- package/dist/plugins/sendgrid/src/provider-contract.ts +14 -0
- package/dist/plugins/sendgrid/test/manifest.test.ts +80 -0
- package/dist/plugins/sendgrid/tsconfig.json +8 -0
- package/dist/plugins/twenty/README.md +78 -0
- package/dist/plugins/twenty/package.json +27 -0
- package/dist/plugins/twenty/scripts/__tests__/sync-thinkwork-app.test.mjs +67 -0
- package/dist/plugins/twenty/scripts/sync-thinkwork-app.mjs +185 -0
- package/dist/plugins/twenty/scripts/wire-thinkwork-workflow.mjs +658 -0
- package/dist/plugins/twenty/smoke/twenty-managed-app-smoke.mjs +359 -0
- package/dist/plugins/twenty/smoke/twenty-mcp-oauth-smoke.mjs +574 -0
- package/dist/plugins/twenty/src/api/cutover.ts +209 -0
- package/dist/plugins/twenty/src/deployment/managed-app.ts +253 -0
- package/dist/plugins/twenty/src/index.ts +55 -0
- package/dist/plugins/twenty/src/manifest.ts +259 -0
- package/dist/plugins/twenty/terraform/twenty/README.md +97 -0
- package/dist/plugins/twenty/terraform/twenty/main.tf +829 -0
- package/dist/plugins/twenty/terraform/twenty/outputs.tf +79 -0
- package/dist/plugins/twenty/terraform/twenty/variables.tf +268 -0
- package/dist/plugins/twenty/test/api/cutover.test.ts +183 -0
- package/dist/plugins/twenty/test/manifest.test.ts +463 -0
- package/dist/plugins/twenty/tsconfig.json +9 -0
- package/dist/plugins/twenty/twenty-app/.nvmrc +1 -0
- package/dist/plugins/twenty/twenty-app/README.md +148 -0
- package/dist/plugins/twenty/twenty-app/package.json +30 -0
- package/dist/plugins/twenty/twenty-app/src/application-config.ts +44 -0
- package/dist/plugins/twenty/twenty-app/src/constants/universal-identifiers.ts +18 -0
- package/dist/plugins/twenty/twenty-app/src/default-role.ts +24 -0
- package/dist/plugins/twenty/twenty-app/src/front-components/thinkwork-settings.front-component.tsx +299 -0
- package/dist/plugins/twenty/twenty-app/src/logic-functions/thinkwork-webhook.logic-function.ts +354 -0
- package/dist/plugins/twenty/twenty-app/tsconfig.json +14 -0
- package/dist/plugins/twenty/twenty-app/yarn.lock +4144 -0
- package/dist/plugins/workos-auth/package.json +22 -0
- package/dist/plugins/workos-auth/src/index.ts +30 -0
- package/dist/plugins/workos-auth/src/manifest.ts +40 -0
- package/dist/plugins/workos-auth/src/provider-contract.ts +39 -0
- package/dist/plugins/workos-auth/test/manifest.test.ts +94 -0
- package/dist/plugins/workos-auth/tsconfig.json +8 -0
- package/dist/scripts/bootstrap-workspace.sh +162 -0
- package/dist/scripts/post-deploy.sh +290 -0
- package/dist/terraform/examples/greenfield/main.tf +903 -75
- package/dist/terraform/examples/greenfield/terraform.tfvars.example +67 -8
- package/dist/terraform/modules/app/agentcore-code-interpreter/Dockerfile.sandbox-base +2 -2
- package/dist/terraform/modules/app/agentcore-code-interpreter/README.md +8 -9
- package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/sitecustomize.py +227 -0
- package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/test_sitecustomize.py +277 -0
- package/dist/terraform/modules/app/agentcore-memory/README.md +6 -6
- package/dist/terraform/modules/app/agentcore-memory/main.tf +1 -1
- package/dist/terraform/modules/app/agentcore-memory/scripts/create_or_find_memory.sh +40 -9
- package/dist/terraform/modules/app/agentcore-pi/README.md +61 -0
- package/dist/terraform/modules/app/agentcore-pi/main.tf +453 -0
- package/dist/terraform/modules/app/agentcore-pi/outputs.tf +38 -0
- package/dist/terraform/modules/app/agentcore-pi/variables.tf +145 -0
- package/dist/terraform/modules/app/agentcore-platform/main.tf +83 -0
- package/dist/terraform/modules/app/agentcore-runtime/main.tf +9 -11
- package/dist/terraform/modules/app/appsync-subscriptions/main.tf +5 -1
- package/dist/terraform/modules/app/customer-domain/main.tf +483 -0
- package/dist/terraform/modules/app/deployment-control-plane/README.md +47 -0
- package/dist/terraform/modules/app/deployment-control-plane/buildspec.yml +24 -0
- package/dist/terraform/modules/app/deployment-control-plane/main.tf +614 -0
- package/dist/terraform/modules/app/deployment-control-plane/outputs.tf +54 -0
- package/dist/terraform/modules/app/deployment-control-plane/runner.py +4720 -0
- package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +3026 -0
- package/dist/terraform/modules/app/deployment-control-plane/variables.tf +96 -0
- package/dist/terraform/modules/app/hindsight-memory/README.md +25 -23
- package/dist/terraform/modules/app/hindsight-memory/main.tf +26 -2
- package/dist/terraform/modules/app/lambda-api/eval-fanout.tf +17 -50
- package/dist/terraform/modules/app/lambda-api/handlers.tf +1290 -679
- package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +933 -0
- package/dist/terraform/modules/app/lambda-api/main.tf +14 -527
- package/dist/terraform/modules/app/lambda-api/mcp-oauth.tf +3 -19
- package/dist/terraform/modules/app/lambda-api/outputs.tf +50 -6
- package/dist/terraform/modules/app/lambda-api/runtime-config.tf +163 -0
- package/dist/terraform/modules/app/lambda-api/slack-app-secrets.tf +3 -1
- package/dist/terraform/modules/app/lambda-api/stripe-secrets.tf +3 -1
- package/dist/terraform/modules/app/lambda-api/variables.tf +240 -53
- package/dist/terraform/modules/app/lambda-api/workspace-events.tf +2 -25
- package/dist/terraform/modules/app/ses-email/main.tf +143 -30
- package/dist/terraform/modules/app/static-site/main.tf +4 -3
- package/dist/terraform/modules/app/www-dns/main.tf +45 -5
- package/dist/terraform/modules/app/www-dns/outputs.tf +10 -0
- package/dist/terraform/modules/app/www-dns/variables.tf +24 -0
- package/dist/terraform/modules/data/aurora-postgres/main.tf +15 -1
- package/dist/terraform/modules/data/compliance-exports-bucket/main.tf +1 -1
- package/dist/terraform/modules/data/compliance-exports-bucket/variables.tf +6 -0
- package/dist/terraform/modules/foundation/cognito/main.tf +167 -11
- package/dist/terraform/modules/foundation/cognito/outputs.tf +5 -0
- package/dist/terraform/modules/foundation/cognito/variables.tf +110 -0
- package/dist/terraform/modules/foundation/vpc/main.tf +45 -3
- package/dist/terraform/modules/foundation/vpc/outputs.tf +20 -0
- package/dist/terraform/modules/foundation/vpc/variables.tf +18 -0
- package/dist/terraform/modules/thinkwork/README.md +71 -0
- package/dist/terraform/modules/thinkwork/main.tf +1325 -174
- package/dist/terraform/modules/thinkwork/outputs.tf +457 -24
- package/dist/terraform/modules/thinkwork/variables.tf +1169 -93
- package/dist/terraform/schema.graphql +82 -9
- package/dist/workspace-defaults/files/AGENTS.md +344 -0
- package/dist/workspace-defaults/files/CONTEXT.md +8 -0
- package/dist/workspace-defaults/files/GUARDRAILS.md +51 -0
- package/dist/workspace-defaults/files/MEMORY_GUIDE.md +65 -0
- package/dist/workspace-defaults/files/ROUTER.md +24 -0
- package/dist/workspace-defaults/files/SPACE.md +62 -0
- package/dist/workspace-defaults/files/TOOLS.md +65 -0
- package/dist/workspace-defaults/files/USER.md +40 -0
- package/dist/workspace-defaults/files/mcp.json +3 -0
- package/dist/workspace-defaults/files/memory/contacts.md +13 -0
- package/dist/workspace-defaults/files/memory/lessons.md +13 -0
- package/dist/workspace-defaults/files/memory/preferences.md +12 -0
- package/dist/workspace-defaults/files/skills/.gitkeep +1 -0
- package/dist/workspace-defaults/files/skills/artifact-builder/SKILL.md +79 -0
- package/dist/workspace-defaults/files/skills/artifact-builder/references/crm-dashboard.md +166 -0
- package/dist/workspace-defaults/files/skills/automation-loop-designer/SKILL.md +120 -0
- package/dist/workspace-defaults/files/skills/skill-creator/LICENSE.txt +202 -0
- package/dist/workspace-defaults/files/skills/skill-creator/SKILL.md +485 -0
- package/dist/workspace-defaults/files/skills/skill-creator/UPSTREAM.json +124 -0
- package/dist/workspace-defaults/files/skills/skill-creator/agents/analyzer.md +274 -0
- package/dist/workspace-defaults/files/skills/skill-creator/agents/comparator.md +202 -0
- package/dist/workspace-defaults/files/skills/skill-creator/agents/grader.md +223 -0
- package/dist/workspace-defaults/files/skills/skill-creator/assets/eval_review.html +146 -0
- package/dist/workspace-defaults/files/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/dist/workspace-defaults/files/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/dist/workspace-defaults/files/skills/skill-creator/references/schemas.md +430 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/__init__.py +0 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/generate_report.py +326 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/improve_description.py +247 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/package_skill.py +136 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/run_eval.py +310 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/run_loop.py +328 -0
- package/dist/workspace-defaults/files/skills/skill-creator/scripts/utils.py +47 -0
- package/package.json +1 -1
- package/dist/terraform/modules/app/agentcore-flue/README.md +0 -58
- package/dist/terraform/modules/app/agentcore-flue/main.tf +0 -323
- package/dist/terraform/modules/app/agentcore-flue/outputs.tf +0 -23
- package/dist/terraform/modules/app/agentcore-flue/variables.tf +0 -97
- package/dist/terraform/modules/app/computer-runtime/README.md +0 -15
- package/dist/terraform/modules/app/computer-runtime/main.tf +0 -406
- package/dist/terraform/modules/app/computer-runtime/outputs.tf +0 -75
- package/dist/terraform/modules/app/computer-runtime/variables.tf +0 -66
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
-- 0069_compliance_schema.sql
|
|
2
|
+
--
|
|
3
|
+
-- Phase 3 U1 of the System Workflows revert + Compliance reframe.
|
|
4
|
+
-- Greenfield `compliance.*` Postgres schema for the SOC2 Type 1
|
|
5
|
+
-- evidence-foundation: append-only audit-event log with per-tenant
|
|
6
|
+
-- hash chain (computed app-side by the U4 drainer Lambda), an outbox
|
|
7
|
+
-- table providing same-transaction durability for control-evidence
|
|
8
|
+
-- writes, an opaque actor pseudonym table erasable on GDPR RTBF, and
|
|
9
|
+
-- an export-jobs table for the admin async-export flow.
|
|
10
|
+
--
|
|
11
|
+
-- The 11 Postgres tables that backed System Workflows + Activation
|
|
12
|
+
-- were dropped in Phase 2 U6 (drizzle/0068_drop_system_workflows_and_activation.sql,
|
|
13
|
+
-- shipped via PR #873 + #878). This migration is greenfield in the
|
|
14
|
+
-- new `compliance.*` namespace; nothing is renamed or repointed.
|
|
15
|
+
--
|
|
16
|
+
-- Plan reference:
|
|
17
|
+
-- docs/plans/2026-05-06-011-feat-compliance-audit-event-log-plan.md
|
|
18
|
+
--
|
|
19
|
+
-- Origin brainstorm:
|
|
20
|
+
-- docs/brainstorms/2026-05-06-system-workflows-revert-compliance-reframe-requirements.md
|
|
21
|
+
--
|
|
22
|
+
-- Apply manually:
|
|
23
|
+
-- psql "$DATABASE_URL" -f packages/database-pg/drizzle/0069_compliance_schema.sql
|
|
24
|
+
-- Then verify:
|
|
25
|
+
-- pnpm db:migrate-manual
|
|
26
|
+
-- psql "$DATABASE_URL" -c "\dt compliance.*"
|
|
27
|
+
--
|
|
28
|
+
-- Role separation note: this migration creates the schema and tables
|
|
29
|
+
-- with default permissions. Aurora role provisioning (compliance_writer,
|
|
30
|
+
-- compliance_reader) lands in U2 via Terraform; until then the dev DB's
|
|
31
|
+
-- default app role can read and write `compliance.*` freely. Phase B
|
|
32
|
+
-- writers (U3-U6) and the drainer (U4) are inert pre-U2 — no rows
|
|
33
|
+
-- accumulate in dev before the role lockdown ships.
|
|
34
|
+
--
|
|
35
|
+
-- Markers (consumed by scripts/db-migrate-manual.sh as the post-deploy drift gate):
|
|
36
|
+
--
|
|
37
|
+
-- creates: compliance.audit_outbox
|
|
38
|
+
-- creates: compliance.audit_events
|
|
39
|
+
-- creates: compliance.actor_pseudonym
|
|
40
|
+
-- creates: compliance.export_jobs
|
|
41
|
+
-- creates: compliance.idx_audit_outbox_pending
|
|
42
|
+
-- creates: compliance.idx_audit_outbox_tenant_enqueued
|
|
43
|
+
-- creates: compliance.idx_audit_events_tenant_occurred
|
|
44
|
+
-- creates: compliance.idx_audit_events_tenant_event_type
|
|
45
|
+
-- creates: compliance.idx_audit_events_actor
|
|
46
|
+
-- creates: compliance.idx_audit_events_control_ids
|
|
47
|
+
-- creates: compliance.uq_audit_events_event_id
|
|
48
|
+
-- creates: compliance.uq_audit_events_outbox_id
|
|
49
|
+
-- creates: compliance.uq_audit_outbox_event_id
|
|
50
|
+
-- creates: compliance.idx_actor_pseudonym_user
|
|
51
|
+
-- creates: compliance.idx_actor_pseudonym_email_hash
|
|
52
|
+
-- creates: compliance.idx_export_jobs_tenant_requested
|
|
53
|
+
-- creates: compliance.idx_export_jobs_actor_requested
|
|
54
|
+
-- creates-constraint: compliance.audit_events.audit_events_actor_type_allowed
|
|
55
|
+
-- These two prefix constraints were renamed to *_v2 by 0088 (finance pilot
|
|
56
|
+
-- extended the event_type prefixes). Markers updated to the post-0088 names
|
|
57
|
+
-- so the drift reporter resolves them via pg_constraint; the original names
|
|
58
|
+
-- are guaranteed absent in any DB where 0088 has applied.
|
|
59
|
+
-- creates-constraint: compliance.audit_events.audit_events_event_type_prefix_v2
|
|
60
|
+
-- creates-constraint: compliance.audit_outbox.audit_outbox_event_type_prefix_v2
|
|
61
|
+
-- creates-constraint: compliance.export_jobs.export_jobs_format_allowed
|
|
62
|
+
-- creates-constraint: compliance.export_jobs.export_jobs_status_allowed
|
|
63
|
+
-- creates-constraint: compliance.actor_pseudonym.actor_pseudonym_actor_type_allowed
|
|
64
|
+
-- creates-function: compliance.raise_immutable
|
|
65
|
+
-- creates-trigger: compliance.audit_events.audit_events_block_update
|
|
66
|
+
-- creates-trigger: compliance.audit_events.audit_events_block_delete
|
|
67
|
+
-- creates-trigger: compliance.audit_events.audit_events_block_truncate
|
|
68
|
+
|
|
69
|
+
\set ON_ERROR_STOP on
|
|
70
|
+
|
|
71
|
+
BEGIN;
|
|
72
|
+
|
|
73
|
+
SET LOCAL lock_timeout = '5s';
|
|
74
|
+
SET LOCAL statement_timeout = '60s';
|
|
75
|
+
|
|
76
|
+
-- Refuse to apply against an unexpected DB. Hand-rolled migrations are
|
|
77
|
+
-- applied by an operator and a stale DATABASE_URL pointing at a non-dev
|
|
78
|
+
-- target would create the schema in the wrong place.
|
|
79
|
+
DO $$
|
|
80
|
+
BEGIN
|
|
81
|
+
IF current_database() != 'thinkwork' THEN
|
|
82
|
+
RAISE EXCEPTION 'wrong database: %, expected thinkwork', current_database();
|
|
83
|
+
END IF;
|
|
84
|
+
END $$;
|
|
85
|
+
|
|
86
|
+
CREATE SCHEMA IF NOT EXISTS compliance;
|
|
87
|
+
COMMENT ON SCHEMA compliance IS
|
|
88
|
+
'SOC2 audit-event log + tamper evidence. App role writes to audit_outbox; drainer writes to audit_events; admin role reads. See docs/plans/2026-05-06-011-feat-compliance-audit-event-log-plan.md.';
|
|
89
|
+
|
|
90
|
+
-- ---------------------------------------------------------------------------
|
|
91
|
+
-- compliance.audit_outbox
|
|
92
|
+
--
|
|
93
|
+
-- Same-transaction durability tier for control-evidence writes (R6).
|
|
94
|
+
-- A resolver or handler inserts here inside its primary `db.transaction`;
|
|
95
|
+
-- if the originating action commits, the outbox row is visible. The U4
|
|
96
|
+
-- single-writer drainer Lambda (reserved-concurrency=1) polls
|
|
97
|
+
-- `FOR UPDATE SKIP LOCKED LIMIT 1`, computes per-tenant prev_hash +
|
|
98
|
+
-- event_hash, writes to audit_events keyed on outbox_id (UNIQUE), and
|
|
99
|
+
-- marks drained_at. Idempotent on outbox_id replay.
|
|
100
|
+
--
|
|
101
|
+
-- The full envelope (R5) is stored here so the drainer is a pure
|
|
102
|
+
-- chain-and-copy operation; outbox rows are not summary records but
|
|
103
|
+
-- the canonical pre-chain representation.
|
|
104
|
+
-- ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
CREATE TABLE IF NOT EXISTS compliance.audit_outbox (
|
|
107
|
+
outbox_id uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
108
|
+
event_id uuid NOT NULL,
|
|
109
|
+
tenant_id uuid NOT NULL,
|
|
110
|
+
occurred_at timestamp with time zone NOT NULL,
|
|
111
|
+
enqueued_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
112
|
+
drained_at timestamp with time zone,
|
|
113
|
+
drainer_error text,
|
|
114
|
+
actor text NOT NULL,
|
|
115
|
+
actor_type text NOT NULL,
|
|
116
|
+
source text NOT NULL,
|
|
117
|
+
event_type text NOT NULL,
|
|
118
|
+
resource_type text,
|
|
119
|
+
resource_id text,
|
|
120
|
+
action text,
|
|
121
|
+
outcome text,
|
|
122
|
+
request_id text,
|
|
123
|
+
thread_id uuid,
|
|
124
|
+
agent_id uuid,
|
|
125
|
+
payload jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
126
|
+
payload_schema_version integer NOT NULL DEFAULT 1,
|
|
127
|
+
control_ids text[] NOT NULL DEFAULT ARRAY[]::text[],
|
|
128
|
+
payload_redacted_fields text[] NOT NULL DEFAULT ARRAY[]::text[],
|
|
129
|
+
payload_oversize_s3_key text,
|
|
130
|
+
CONSTRAINT audit_outbox_event_type_prefix CHECK (
|
|
131
|
+
event_type ~ '^(auth|user|agent|mcp|workspace|data|policy|approval)\.'
|
|
132
|
+
)
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
COMMENT ON TABLE compliance.audit_outbox IS
|
|
136
|
+
'Pre-chain durability tier. Writers insert in caller transaction; U4 drainer Lambda single-writer polls FOR UPDATE SKIP LOCKED, computes per-tenant chain, inserts to audit_events.';
|
|
137
|
+
|
|
138
|
+
CREATE UNIQUE INDEX IF NOT EXISTS uq_audit_outbox_event_id
|
|
139
|
+
ON compliance.audit_outbox (event_id);
|
|
140
|
+
|
|
141
|
+
-- Partial index over un-drained rows so the drainer's poll query stays
|
|
142
|
+
-- O(N pending) regardless of total outbox volume.
|
|
143
|
+
CREATE INDEX IF NOT EXISTS idx_audit_outbox_pending
|
|
144
|
+
ON compliance.audit_outbox (enqueued_at)
|
|
145
|
+
WHERE drained_at IS NULL;
|
|
146
|
+
|
|
147
|
+
CREATE INDEX IF NOT EXISTS idx_audit_outbox_tenant_enqueued
|
|
148
|
+
ON compliance.audit_outbox (tenant_id, enqueued_at);
|
|
149
|
+
|
|
150
|
+
-- ---------------------------------------------------------------------------
|
|
151
|
+
-- compliance.audit_events
|
|
152
|
+
--
|
|
153
|
+
-- Append-only audit-event log (R5). Per-tenant hash chain via prev_hash
|
|
154
|
+
-- + event_hash, both computed app-side by the U4 drainer Lambda. INSERT
|
|
155
|
+
-- is the only legal mutation; UPDATE and DELETE are rejected by the
|
|
156
|
+
-- compliance.raise_immutable() trigger below as defense-in-depth on top
|
|
157
|
+
-- of the role grants U2 ships.
|
|
158
|
+
--
|
|
159
|
+
-- The 22-field envelope plus payload_oversize_s3_key (oversized payloads
|
|
160
|
+
-- spill to S3 with the key reference recorded here) and outbox_id (link
|
|
161
|
+
-- back to the originating outbox row, idempotency key for drainer
|
|
162
|
+
-- replay).
|
|
163
|
+
--
|
|
164
|
+
-- prev_hash is nullable: the genesis event in each tenant's chain has
|
|
165
|
+
-- no prior hash. event_hash is non-nullable: every row commits to its
|
|
166
|
+
-- own hash so the chain is verifiable from any anchor backwards.
|
|
167
|
+
-- ---------------------------------------------------------------------------
|
|
168
|
+
|
|
169
|
+
CREATE TABLE IF NOT EXISTS compliance.audit_events (
|
|
170
|
+
event_id uuid PRIMARY KEY NOT NULL,
|
|
171
|
+
outbox_id uuid NOT NULL,
|
|
172
|
+
tenant_id uuid NOT NULL,
|
|
173
|
+
occurred_at timestamp with time zone NOT NULL,
|
|
174
|
+
recorded_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
175
|
+
actor text NOT NULL,
|
|
176
|
+
actor_type text NOT NULL,
|
|
177
|
+
source text NOT NULL,
|
|
178
|
+
event_type text NOT NULL,
|
|
179
|
+
resource_type text,
|
|
180
|
+
resource_id text,
|
|
181
|
+
action text,
|
|
182
|
+
outcome text,
|
|
183
|
+
request_id text,
|
|
184
|
+
thread_id uuid,
|
|
185
|
+
agent_id uuid,
|
|
186
|
+
payload jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
187
|
+
payload_schema_version integer NOT NULL DEFAULT 1,
|
|
188
|
+
control_ids text[] NOT NULL DEFAULT ARRAY[]::text[],
|
|
189
|
+
payload_redacted_fields text[] NOT NULL DEFAULT ARRAY[]::text[],
|
|
190
|
+
payload_oversize_s3_key text,
|
|
191
|
+
prev_hash char(64),
|
|
192
|
+
event_hash char(64) NOT NULL,
|
|
193
|
+
CONSTRAINT audit_events_actor_type_allowed CHECK (
|
|
194
|
+
actor_type IN ('user', 'system', 'agent')
|
|
195
|
+
),
|
|
196
|
+
CONSTRAINT audit_events_event_type_prefix CHECK (
|
|
197
|
+
event_type ~ '^(auth|user|agent|mcp|workspace|data|policy|approval)\.'
|
|
198
|
+
)
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
COMMENT ON TABLE compliance.audit_events IS
|
|
202
|
+
'Append-only audit-event log. Written ONLY by the U4 drainer Lambda. INSERT-only by role + immutability triggers. Per-tenant hash chain (prev_hash, event_hash). Tamper evidence anchored periodically by U8 to S3 Object Lock.';
|
|
203
|
+
|
|
204
|
+
CREATE UNIQUE INDEX IF NOT EXISTS uq_audit_events_event_id
|
|
205
|
+
ON compliance.audit_events (event_id);
|
|
206
|
+
|
|
207
|
+
-- outbox_id UNIQUE provides drainer-replay idempotency: a re-invocation
|
|
208
|
+
-- on the same outbox row attempts an INSERT that conflicts and is
|
|
209
|
+
-- handled by ON CONFLICT (outbox_id) DO NOTHING in the drainer.
|
|
210
|
+
CREATE UNIQUE INDEX IF NOT EXISTS uq_audit_events_outbox_id
|
|
211
|
+
ON compliance.audit_events (outbox_id);
|
|
212
|
+
|
|
213
|
+
-- Per-tenant time-ordered listing — admin Events list default sort.
|
|
214
|
+
CREATE INDEX IF NOT EXISTS idx_audit_events_tenant_occurred
|
|
215
|
+
ON compliance.audit_events (tenant_id, occurred_at DESC);
|
|
216
|
+
|
|
217
|
+
-- Filter by event_type (R8) often combined with tenant + time.
|
|
218
|
+
CREATE INDEX IF NOT EXISTS idx_audit_events_tenant_event_type
|
|
219
|
+
ON compliance.audit_events (tenant_id, event_type, occurred_at DESC);
|
|
220
|
+
|
|
221
|
+
-- Filter by actor (R8) — actor stored as opaque text id.
|
|
222
|
+
CREATE INDEX IF NOT EXISTS idx_audit_events_actor
|
|
223
|
+
ON compliance.audit_events (actor);
|
|
224
|
+
|
|
225
|
+
-- Control-evidence exports filter by control_ids[] (e.g. CC6.1, CC8.1).
|
|
226
|
+
-- GIN supports `control_ids @> ARRAY['CC6.1']` membership lookups.
|
|
227
|
+
CREATE INDEX IF NOT EXISTS idx_audit_events_control_ids
|
|
228
|
+
ON compliance.audit_events USING GIN (control_ids);
|
|
229
|
+
|
|
230
|
+
-- ---------------------------------------------------------------------------
|
|
231
|
+
-- compliance.actor_pseudonym
|
|
232
|
+
--
|
|
233
|
+
-- GDPR right-to-be-forgotten enabler (Decision #5). The audit chain
|
|
234
|
+
-- hashes the opaque `actor` text id, never PII. This table maps
|
|
235
|
+
-- actor_id → user_id + email_hash. RTBF erasure deletes the pseudonym
|
|
236
|
+
-- row; the chain remains valid (no audit_events row mutates) but
|
|
237
|
+
-- actor → person resolution is lost. EDPB recognizes this as effective
|
|
238
|
+
-- erasure when re-identification is no longer reasonably possible.
|
|
239
|
+
--
|
|
240
|
+
-- email_hash is sha256 of the lowercased email — supports typeahead
|
|
241
|
+
-- lookup in the admin Events list filter without storing plaintext.
|
|
242
|
+
-- ---------------------------------------------------------------------------
|
|
243
|
+
|
|
244
|
+
CREATE TABLE IF NOT EXISTS compliance.actor_pseudonym (
|
|
245
|
+
actor_id uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
246
|
+
user_id uuid,
|
|
247
|
+
email_hash char(64),
|
|
248
|
+
actor_type text NOT NULL,
|
|
249
|
+
display_name text,
|
|
250
|
+
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
251
|
+
CONSTRAINT actor_pseudonym_actor_type_allowed CHECK (
|
|
252
|
+
actor_type IN ('user', 'system', 'agent')
|
|
253
|
+
)
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
COMMENT ON TABLE compliance.actor_pseudonym IS
|
|
257
|
+
'Opaque actor_id ↔ user_id + email_hash mapping. GDPR RTBF: deleting a row breaks actor→person resolution while leaving the audit chain intact. Hash chain hashes actor_id, never PII.';
|
|
258
|
+
|
|
259
|
+
CREATE INDEX IF NOT EXISTS idx_actor_pseudonym_user
|
|
260
|
+
ON compliance.actor_pseudonym (user_id)
|
|
261
|
+
WHERE user_id IS NOT NULL;
|
|
262
|
+
|
|
263
|
+
CREATE INDEX IF NOT EXISTS idx_actor_pseudonym_email_hash
|
|
264
|
+
ON compliance.actor_pseudonym (email_hash)
|
|
265
|
+
WHERE email_hash IS NOT NULL;
|
|
266
|
+
|
|
267
|
+
-- ---------------------------------------------------------------------------
|
|
268
|
+
-- compliance.export_jobs
|
|
269
|
+
--
|
|
270
|
+
-- Async CSV/JSON export tracking (R9, U11). createAuditExport mutation
|
|
271
|
+
-- inserts a queued row, sends an SQS message, and returns job_id. The
|
|
272
|
+
-- export-runner Lambda transitions queued → running → complete (or
|
|
273
|
+
-- failed), writes the multipart upload to a non-Object-Lock S3 prefix,
|
|
274
|
+
-- and publishes a 15-minute presigned URL.
|
|
275
|
+
--
|
|
276
|
+
-- 90-day max date range and 10/hour/admin rate limit are enforced at
|
|
277
|
+
-- the resolver layer (U11), not in the schema. The schema permits any
|
|
278
|
+
-- filter shape but the GraphQL mutation rejects out-of-bounds requests
|
|
279
|
+
-- before the row lands.
|
|
280
|
+
-- ---------------------------------------------------------------------------
|
|
281
|
+
|
|
282
|
+
CREATE TABLE IF NOT EXISTS compliance.export_jobs (
|
|
283
|
+
job_id uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
284
|
+
tenant_id uuid NOT NULL,
|
|
285
|
+
requested_by_actor_id uuid NOT NULL,
|
|
286
|
+
filter jsonb NOT NULL,
|
|
287
|
+
format text NOT NULL,
|
|
288
|
+
status text NOT NULL DEFAULT 'queued',
|
|
289
|
+
s3_key text,
|
|
290
|
+
presigned_url text,
|
|
291
|
+
presigned_url_expires_at timestamp with time zone,
|
|
292
|
+
job_error text,
|
|
293
|
+
requested_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
294
|
+
started_at timestamp with time zone,
|
|
295
|
+
completed_at timestamp with time zone,
|
|
296
|
+
CONSTRAINT export_jobs_format_allowed CHECK (
|
|
297
|
+
format IN ('csv', 'json')
|
|
298
|
+
),
|
|
299
|
+
CONSTRAINT export_jobs_status_allowed CHECK (
|
|
300
|
+
status IN ('queued', 'running', 'complete', 'failed')
|
|
301
|
+
)
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
COMMENT ON TABLE compliance.export_jobs IS
|
|
305
|
+
'Admin async-export job tracking. createAuditExport mutation enforces 90-day max range + 10/hour/admin rate limit before insert. export-runner Lambda streams CSV/NDJSON to S3 + publishes 15min presigned URL.';
|
|
306
|
+
|
|
307
|
+
CREATE INDEX IF NOT EXISTS idx_export_jobs_tenant_requested
|
|
308
|
+
ON compliance.export_jobs (tenant_id, requested_at DESC);
|
|
309
|
+
|
|
310
|
+
-- Rate-limit check at the resolver layer queries by (tenant, actor, recent window).
|
|
311
|
+
CREATE INDEX IF NOT EXISTS idx_export_jobs_actor_requested
|
|
312
|
+
ON compliance.export_jobs (tenant_id, requested_by_actor_id, requested_at DESC);
|
|
313
|
+
|
|
314
|
+
-- ---------------------------------------------------------------------------
|
|
315
|
+
-- Immutability trigger function + per-table triggers
|
|
316
|
+
--
|
|
317
|
+
-- Defense-in-depth on top of the role grants U2 ships. Even if the
|
|
318
|
+
-- writer role is mis-granted UPDATE/DELETE/TRUNCATE on audit_events
|
|
319
|
+
-- (config drift, mistaken break-glass grant, future privileged role),
|
|
320
|
+
-- the triggers RAISE EXCEPTION before the change applies.
|
|
321
|
+
--
|
|
322
|
+
-- TRUNCATE bypasses BEFORE DELETE triggers in Postgres — it has its own
|
|
323
|
+
-- BEFORE TRUNCATE trigger that fires FOR EACH STATEMENT. Without the
|
|
324
|
+
-- truncate trigger, an actor with TRUNCATE privilege could wipe the
|
|
325
|
+
-- entire audit log without producing the immutability error. The
|
|
326
|
+
-- trigger function below switches on TG_OP so a single function serves
|
|
327
|
+
-- ROW-level (UPDATE/DELETE) and STATEMENT-level (TRUNCATE) firings.
|
|
328
|
+
--
|
|
329
|
+
-- DROP TRIGGER IF EXISTS + CREATE TRIGGER is the portable idempotent
|
|
330
|
+
-- pattern; CREATE OR REPLACE TRIGGER is Postgres 14+ but DROP IF EXISTS
|
|
331
|
+
-- works identically on every supported version.
|
|
332
|
+
-- ---------------------------------------------------------------------------
|
|
333
|
+
|
|
334
|
+
CREATE OR REPLACE FUNCTION compliance.raise_immutable()
|
|
335
|
+
RETURNS TRIGGER
|
|
336
|
+
LANGUAGE plpgsql
|
|
337
|
+
AS $$
|
|
338
|
+
BEGIN
|
|
339
|
+
IF TG_OP = 'TRUNCATE' THEN
|
|
340
|
+
RAISE EXCEPTION 'compliance.audit_events rows are immutable (TRUNCATE blocked)';
|
|
341
|
+
END IF;
|
|
342
|
+
RAISE EXCEPTION 'compliance.audit_events rows are immutable (event_id=%)', COALESCE(OLD.event_id::text, NEW.event_id::text);
|
|
343
|
+
END;
|
|
344
|
+
$$;
|
|
345
|
+
|
|
346
|
+
DROP TRIGGER IF EXISTS audit_events_block_update ON compliance.audit_events;
|
|
347
|
+
CREATE TRIGGER audit_events_block_update
|
|
348
|
+
BEFORE UPDATE ON compliance.audit_events
|
|
349
|
+
FOR EACH ROW
|
|
350
|
+
EXECUTE FUNCTION compliance.raise_immutable();
|
|
351
|
+
|
|
352
|
+
DROP TRIGGER IF EXISTS audit_events_block_delete ON compliance.audit_events;
|
|
353
|
+
CREATE TRIGGER audit_events_block_delete
|
|
354
|
+
BEFORE DELETE ON compliance.audit_events
|
|
355
|
+
FOR EACH ROW
|
|
356
|
+
EXECUTE FUNCTION compliance.raise_immutable();
|
|
357
|
+
|
|
358
|
+
DROP TRIGGER IF EXISTS audit_events_block_truncate ON compliance.audit_events;
|
|
359
|
+
CREATE TRIGGER audit_events_block_truncate
|
|
360
|
+
BEFORE TRUNCATE ON compliance.audit_events
|
|
361
|
+
FOR EACH STATEMENT
|
|
362
|
+
EXECUTE FUNCTION compliance.raise_immutable();
|
|
363
|
+
|
|
364
|
+
COMMIT;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
-- 0070_compliance_aurora_roles.sql
|
|
2
|
+
--
|
|
3
|
+
-- Phase 3 U2 of the System Workflows revert + Compliance reframe.
|
|
4
|
+
-- Provisions the three Aurora roles that scope per-tier access to the
|
|
5
|
+
-- compliance.* schema introduced in U1 (drizzle/0069_compliance_schema.sql,
|
|
6
|
+
-- merged via PR #880):
|
|
7
|
+
--
|
|
8
|
+
-- - compliance_writer: USAGE on schema + INSERT only on audit_outbox
|
|
9
|
+
-- and export_jobs. Used by Yoga resolvers and
|
|
10
|
+
-- Lambda handlers via the U3 emitAuditEvent
|
|
11
|
+
-- helper.
|
|
12
|
+
-- - compliance_drainer: USAGE + SELECT/UPDATE on audit_outbox + SELECT
|
|
13
|
+
-- on actor_pseudonym + INSERT only on
|
|
14
|
+
-- audit_events. Used exclusively by the U4
|
|
15
|
+
-- single-writer outbox drainer Lambda
|
|
16
|
+
-- (reserved-concurrency=1).
|
|
17
|
+
-- - compliance_reader: USAGE + SELECT-only on all four compliance.*
|
|
18
|
+
-- tables. Used by the graphql-http Lambda for
|
|
19
|
+
-- the U10 admin Compliance section read paths.
|
|
20
|
+
--
|
|
21
|
+
-- Plan reference:
|
|
22
|
+
-- docs/plans/2026-05-07-001-feat-compliance-u2-aurora-roles-plan.md
|
|
23
|
+
-- docs/plans/2026-05-06-011-feat-compliance-audit-event-log-plan.md
|
|
24
|
+
--
|
|
25
|
+
-- Apply manually:
|
|
26
|
+
-- The bootstrap helper script wraps this file with psql variable
|
|
27
|
+
-- substitution + Secrets Manager population:
|
|
28
|
+
-- STAGE=dev bash scripts/bootstrap-compliance-roles.sh
|
|
29
|
+
-- Direct apply (advanced — must supply all three passwords):
|
|
30
|
+
-- psql "$DATABASE_URL" \
|
|
31
|
+
-- -v writer_pass="$COMPLIANCE_WRITER_PASS" \
|
|
32
|
+
-- -v drainer_pass="$COMPLIANCE_DRAINER_PASS" \
|
|
33
|
+
-- -v reader_pass="$COMPLIANCE_READER_PASS" \
|
|
34
|
+
-- -f packages/database-pg/drizzle/0070_compliance_aurora_roles.sql
|
|
35
|
+
--
|
|
36
|
+
-- The DO $$ ... $$ blocks make role creation idempotent (re-running with
|
|
37
|
+
-- new passwords runs ALTER ROLE; re-running with same passwords is a
|
|
38
|
+
-- no-op). GRANT statements are inherently idempotent in PostgreSQL.
|
|
39
|
+
--
|
|
40
|
+
-- Markers (consumed by scripts/db-migrate-manual.sh as the post-deploy drift gate):
|
|
41
|
+
--
|
|
42
|
+
-- creates-role: compliance_writer
|
|
43
|
+
-- creates-role: compliance_drainer
|
|
44
|
+
-- creates-role: compliance_reader
|
|
45
|
+
|
|
46
|
+
\set ON_ERROR_STOP on
|
|
47
|
+
|
|
48
|
+
BEGIN;
|
|
49
|
+
|
|
50
|
+
SET LOCAL lock_timeout = '5s';
|
|
51
|
+
SET LOCAL statement_timeout = '60s';
|
|
52
|
+
SET LOCAL "thinkwork.writer_pass" = :'writer_pass';
|
|
53
|
+
SET LOCAL "thinkwork.drainer_pass" = :'drainer_pass';
|
|
54
|
+
SET LOCAL "thinkwork.reader_pass" = :'reader_pass';
|
|
55
|
+
|
|
56
|
+
-- Refuse to apply against an unexpected DB. Hand-rolled migrations are
|
|
57
|
+
-- applied by an operator and a stale DATABASE_URL pointing at a non-dev
|
|
58
|
+
-- target would create roles in the wrong cluster.
|
|
59
|
+
DO $$
|
|
60
|
+
BEGIN
|
|
61
|
+
IF current_database() != 'thinkwork' THEN
|
|
62
|
+
RAISE EXCEPTION 'wrong database: %, expected thinkwork', current_database();
|
|
63
|
+
END IF;
|
|
64
|
+
END $$;
|
|
65
|
+
|
|
66
|
+
-- Refuse to apply if the U1 compliance schema is missing. PostgreSQL
|
|
67
|
+
-- CREATE ROLE is NOT transactional — it commits to pg_authid before the
|
|
68
|
+
-- subsequent GRANT statements run, so a 0070 apply against a database
|
|
69
|
+
-- without 0069 would leave three roles with passwords but zero grants.
|
|
70
|
+
-- The drift gate then probes pg_roles and reports APPLIED, masking the
|
|
71
|
+
-- partial state. This guard converts the silent partial failure into a
|
|
72
|
+
-- hard stop before any role creation.
|
|
73
|
+
DO $$
|
|
74
|
+
BEGIN
|
|
75
|
+
IF NOT EXISTS (SELECT FROM information_schema.schemata WHERE schema_name = 'compliance') THEN
|
|
76
|
+
RAISE EXCEPTION 'compliance schema missing: apply drizzle/0069_compliance_schema.sql first (U1, PR #880)';
|
|
77
|
+
END IF;
|
|
78
|
+
END $$;
|
|
79
|
+
|
|
80
|
+
-- ---------------------------------------------------------------------------
|
|
81
|
+
-- Role creation (idempotent)
|
|
82
|
+
--
|
|
83
|
+
-- Each block creates the role if missing, otherwise rotates the password
|
|
84
|
+
-- via ALTER ROLE. CREATE ROLE has no IF NOT EXISTS form prior to PG 16,
|
|
85
|
+
-- so the DO $$ ... pg_roles existence check is the portable idempotent
|
|
86
|
+
-- pattern. ALTER ROLE on the same role with the same password is a
|
|
87
|
+
-- no-op, so re-running with stable passwords is safe.
|
|
88
|
+
-- ---------------------------------------------------------------------------
|
|
89
|
+
|
|
90
|
+
DO $$
|
|
91
|
+
BEGIN
|
|
92
|
+
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'compliance_writer') THEN
|
|
93
|
+
EXECUTE format('CREATE ROLE compliance_writer WITH LOGIN PASSWORD %L', current_setting('thinkwork.writer_pass'));
|
|
94
|
+
ELSE
|
|
95
|
+
EXECUTE format('ALTER ROLE compliance_writer WITH LOGIN PASSWORD %L', current_setting('thinkwork.writer_pass'));
|
|
96
|
+
END IF;
|
|
97
|
+
END $$;
|
|
98
|
+
|
|
99
|
+
DO $$
|
|
100
|
+
BEGIN
|
|
101
|
+
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'compliance_drainer') THEN
|
|
102
|
+
EXECUTE format('CREATE ROLE compliance_drainer WITH LOGIN PASSWORD %L', current_setting('thinkwork.drainer_pass'));
|
|
103
|
+
ELSE
|
|
104
|
+
EXECUTE format('ALTER ROLE compliance_drainer WITH LOGIN PASSWORD %L', current_setting('thinkwork.drainer_pass'));
|
|
105
|
+
END IF;
|
|
106
|
+
END $$;
|
|
107
|
+
|
|
108
|
+
DO $$
|
|
109
|
+
BEGIN
|
|
110
|
+
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'compliance_reader') THEN
|
|
111
|
+
EXECUTE format('CREATE ROLE compliance_reader WITH LOGIN PASSWORD %L', current_setting('thinkwork.reader_pass'));
|
|
112
|
+
ELSE
|
|
113
|
+
EXECUTE format('ALTER ROLE compliance_reader WITH LOGIN PASSWORD %L', current_setting('thinkwork.reader_pass'));
|
|
114
|
+
END IF;
|
|
115
|
+
END $$;
|
|
116
|
+
|
|
117
|
+
-- ---------------------------------------------------------------------------
|
|
118
|
+
-- Schema-level USAGE for all three roles
|
|
119
|
+
-- ---------------------------------------------------------------------------
|
|
120
|
+
|
|
121
|
+
GRANT USAGE ON SCHEMA compliance TO compliance_writer, compliance_drainer, compliance_reader;
|
|
122
|
+
|
|
123
|
+
-- ---------------------------------------------------------------------------
|
|
124
|
+
-- compliance_writer — INSERT only on audit_outbox + export_jobs
|
|
125
|
+
--
|
|
126
|
+
-- The U3 emitAuditEvent helper inserts into audit_outbox in the caller's
|
|
127
|
+
-- transaction. The U11 createAuditExport mutation inserts into
|
|
128
|
+
-- export_jobs. Writer has no SELECT, no UPDATE, no DELETE, no access to
|
|
129
|
+
-- audit_events (only the drainer writes there) or actor_pseudonym (read
|
|
130
|
+
-- via the reader role for typeahead lookups in the admin UI).
|
|
131
|
+
-- ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
GRANT INSERT ON compliance.audit_outbox TO compliance_writer;
|
|
134
|
+
GRANT INSERT ON compliance.export_jobs TO compliance_writer;
|
|
135
|
+
|
|
136
|
+
-- ---------------------------------------------------------------------------
|
|
137
|
+
-- compliance_drainer — pulls outbox, computes hash chain, writes audit_events
|
|
138
|
+
--
|
|
139
|
+
-- SELECT + UPDATE on audit_outbox: poll FOR UPDATE SKIP LOCKED, mark
|
|
140
|
+
-- drained_at on success, write drainer_error on failure.
|
|
141
|
+
-- SELECT on actor_pseudonym: needed if the drainer canonicalizes the
|
|
142
|
+
-- payload with actor_id resolution (Decision #5 in the master plan
|
|
143
|
+
-- keeps actor_id opaque in audit rows; pseudonym lookup is read-only).
|
|
144
|
+
-- INSERT on audit_events: append-only chained log.
|
|
145
|
+
--
|
|
146
|
+
-- No DELETE/TRUNCATE on any table — drainer never removes outbox rows
|
|
147
|
+
-- (drained_at marker is the soft-tombstone) and never modifies historical
|
|
148
|
+
-- audit events. The U1 immutability triggers are belt-and-suspenders on
|
|
149
|
+
-- top of this grant boundary.
|
|
150
|
+
-- ---------------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
GRANT SELECT, UPDATE ON compliance.audit_outbox TO compliance_drainer;
|
|
153
|
+
GRANT SELECT ON compliance.actor_pseudonym TO compliance_drainer;
|
|
154
|
+
GRANT INSERT ON compliance.audit_events TO compliance_drainer;
|
|
155
|
+
|
|
156
|
+
-- ---------------------------------------------------------------------------
|
|
157
|
+
-- compliance_reader — SELECT-only on all four tables
|
|
158
|
+
--
|
|
159
|
+
-- The U10 admin Compliance section reads via this role: events list,
|
|
160
|
+
-- detail drawer, exports filter resolution, verification status panel,
|
|
161
|
+
-- pseudonym typeahead resolution. No write surface; the U11 export
|
|
162
|
+
-- mutation flow uses compliance_writer for the export_jobs INSERT and
|
|
163
|
+
-- only reads via this role.
|
|
164
|
+
-- ---------------------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
GRANT SELECT ON compliance.audit_outbox TO compliance_reader;
|
|
167
|
+
GRANT SELECT ON compliance.audit_events TO compliance_reader;
|
|
168
|
+
GRANT SELECT ON compliance.actor_pseudonym TO compliance_reader;
|
|
169
|
+
GRANT SELECT ON compliance.export_jobs TO compliance_reader;
|
|
170
|
+
|
|
171
|
+
COMMIT;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
-- Add nullable Computer ownership to Threads for the feature-flagged
|
|
2
|
+
-- ThinkWork Computer cutover.
|
|
3
|
+
--
|
|
4
|
+
-- Apply manually:
|
|
5
|
+
-- psql "$DATABASE_URL" -f packages/database-pg/drizzle/0072_threads_computer_ownership.sql
|
|
6
|
+
--
|
|
7
|
+
-- creates-column: public.threads.computer_id
|
|
8
|
+
-- creates: public.idx_threads_computer
|
|
9
|
+
|
|
10
|
+
\set ON_ERROR_STOP on
|
|
11
|
+
|
|
12
|
+
BEGIN;
|
|
13
|
+
|
|
14
|
+
SET LOCAL lock_timeout = '5s';
|
|
15
|
+
SET LOCAL statement_timeout = '120s';
|
|
16
|
+
|
|
17
|
+
ALTER TABLE public.threads
|
|
18
|
+
ADD COLUMN IF NOT EXISTS computer_id uuid REFERENCES public.computers(id);
|
|
19
|
+
|
|
20
|
+
CREATE INDEX IF NOT EXISTS idx_threads_computer
|
|
21
|
+
ON public.threads (tenant_id, computer_id)
|
|
22
|
+
WHERE computer_id IS NOT NULL;
|
|
23
|
+
|
|
24
|
+
COMMIT;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
-- 0073_compliance_tenant_anchor_state.sql
|
|
2
|
+
--
|
|
3
|
+
-- Phase 3 U8a of the System Workflows revert + Compliance reframe.
|
|
4
|
+
-- (Originally drafted as 0071 but renumbered to 0073 to avoid collision
|
|
5
|
+
-- with the unrelated 0071_connector_computer_dispatch_target.sql that
|
|
6
|
+
-- shipped on origin/main concurrently with this work.)
|
|
7
|
+
-- Adds the per-tenant high-water-mark table the anchor Lambda uses to
|
|
8
|
+
-- track which audit_events have been included in a Merkle anchor.
|
|
9
|
+
--
|
|
10
|
+
-- Schema:
|
|
11
|
+
-- compliance.tenant_anchor_state(
|
|
12
|
+
-- tenant_id uuid PRIMARY KEY,
|
|
13
|
+
-- last_anchored_recorded_at timestamptz,
|
|
14
|
+
-- last_anchored_event_id uuid,
|
|
15
|
+
-- last_cadence_id uuid,
|
|
16
|
+
-- updated_at timestamptz NOT NULL DEFAULT now()
|
|
17
|
+
-- )
|
|
18
|
+
--
|
|
19
|
+
-- Anchor advance: at each cadence, the Lambda updates each tenant's row
|
|
20
|
+
-- with the maximum recorded_at across the events included in the cadence
|
|
21
|
+
-- (and the corresponding event_id for tie-breaking on equal timestamps).
|
|
22
|
+
-- The next cadence's chain-head SELECT uses
|
|
23
|
+
-- `recorded_at > last_anchored_recorded_at` (or > '-infinity' for
|
|
24
|
+
-- never-anchored tenants).
|
|
25
|
+
--
|
|
26
|
+
-- Role grants:
|
|
27
|
+
-- compliance_drainer gets SELECT/INSERT/UPDATE (not DELETE) on the new
|
|
28
|
+
-- table. Per master plan U8a Decision #5, the anchor Lambda reuses the
|
|
29
|
+
-- compliance_drainer role for tenant_anchor_state writes rather than
|
|
30
|
+
-- provisioning a 4th Aurora role. The anchor Lambda runs reserved-
|
|
31
|
+
-- concurrency=1 (matching the drainer pattern), so the role widening
|
|
32
|
+
-- is bounded to one concurrent writer.
|
|
33
|
+
--
|
|
34
|
+
-- Plan reference:
|
|
35
|
+
-- docs/plans/2026-05-07-010-feat-compliance-u8a-anchor-lambda-inert-plan.md
|
|
36
|
+
-- docs/plans/2026-05-06-011-feat-compliance-audit-event-log-plan.md
|
|
37
|
+
--
|
|
38
|
+
-- Apply manually (operator step before merging — drift gate currently
|
|
39
|
+
-- disabled per #905):
|
|
40
|
+
-- psql "$DATABASE_URL" -f packages/database-pg/drizzle/0073_compliance_tenant_anchor_state.sql
|
|
41
|
+
--
|
|
42
|
+
-- Markers (consumed by scripts/db-migrate-manual.sh as the post-deploy drift gate):
|
|
43
|
+
--
|
|
44
|
+
-- creates: compliance.tenant_anchor_state
|
|
45
|
+
-- creates: compliance.idx_tenant_anchor_state_updated_at
|
|
46
|
+
|
|
47
|
+
\set ON_ERROR_STOP on
|
|
48
|
+
|
|
49
|
+
BEGIN;
|
|
50
|
+
|
|
51
|
+
SET LOCAL lock_timeout = '5s';
|
|
52
|
+
SET LOCAL statement_timeout = '60s';
|
|
53
|
+
|
|
54
|
+
-- Database guard — ensures we never accidentally apply to a wrong-named
|
|
55
|
+
-- database. Mirrors 0069 + 0070 prologue.
|
|
56
|
+
DO $$
|
|
57
|
+
BEGIN
|
|
58
|
+
IF current_database() NOT IN ('thinkwork', 'postgres') THEN
|
|
59
|
+
RAISE EXCEPTION 'Wrong database: %, expected thinkwork or postgres', current_database();
|
|
60
|
+
END IF;
|
|
61
|
+
END $$;
|
|
62
|
+
|
|
63
|
+
-- ---------------------------------------------------------------------------
|
|
64
|
+
-- compliance.tenant_anchor_state
|
|
65
|
+
--
|
|
66
|
+
-- One row per tenant. The anchor Lambda updates last_anchored_recorded_at
|
|
67
|
+
-- with the maximum recorded_at across the events included in the latest
|
|
68
|
+
-- Merkle cadence's tenant slice (tie-broken by event_id for equal
|
|
69
|
+
-- timestamps). Seeded lazily on first anchor — never-anchored tenants
|
|
70
|
+
-- have no row, and the chain-head SELECT uses
|
|
71
|
+
-- COALESCE(last_anchored_recorded_at, '-infinity'::timestamptz) so they
|
|
72
|
+
-- still surface every event.
|
|
73
|
+
-- ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
CREATE TABLE IF NOT EXISTS compliance.tenant_anchor_state (
|
|
76
|
+
tenant_id uuid PRIMARY KEY,
|
|
77
|
+
last_anchored_recorded_at timestamptz,
|
|
78
|
+
last_anchored_event_id uuid,
|
|
79
|
+
last_cadence_id uuid,
|
|
80
|
+
updated_at timestamptz NOT NULL DEFAULT now()
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
-- Index for the watchdog's eventual "oldest un-anchored tenant" query
|
|
84
|
+
-- (U8b consumes this; U8a creates it inert).
|
|
85
|
+
CREATE INDEX IF NOT EXISTS idx_tenant_anchor_state_updated_at
|
|
86
|
+
ON compliance.tenant_anchor_state (updated_at);
|
|
87
|
+
|
|
88
|
+
-- ---------------------------------------------------------------------------
|
|
89
|
+
-- Grants
|
|
90
|
+
-- ---------------------------------------------------------------------------
|
|
91
|
+
|
|
92
|
+
-- USAGE on schema is already granted to compliance_drainer in 0070; this
|
|
93
|
+
-- restatement is for clarity (idempotent in PostgreSQL).
|
|
94
|
+
GRANT USAGE ON SCHEMA compliance TO compliance_drainer;
|
|
95
|
+
|
|
96
|
+
-- The anchor Lambda needs SELECT (read latest seq), INSERT (seed first
|
|
97
|
+
-- row per tenant), UPDATE (advance high-water-mark). No DELETE — this
|
|
98
|
+
-- table is append-or-update-only.
|
|
99
|
+
GRANT SELECT, INSERT, UPDATE ON compliance.tenant_anchor_state TO compliance_drainer;
|
|
100
|
+
|
|
101
|
+
-- compliance_reader gets SELECT for the eventual U10 admin Compliance UI
|
|
102
|
+
-- (showing per-tenant anchor lag). Read-only by intent.
|
|
103
|
+
GRANT SELECT ON compliance.tenant_anchor_state TO compliance_reader;
|
|
104
|
+
|
|
105
|
+
COMMIT;
|