Repository navigation
feat(projects): enforce Project membership and retire the connector #8590
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
mzxchandra
wants to merge
93
commits into
feat/project-workspace-column-expand
from
codex/project-entity-enforcement
+36,879
−1,702
Draft
Changes from all commits
Commits
Show all changes
93 commits
Select commit
Hold shift + click to select a range
00a83d0
feat(projects): add project identity and lifecycle foundation
mzxchandra aa9b415
feat(projects): create projects with their initial environment
mzxchandra 91cba23
docs(projects): record project files follow-up
mzxchandra 0980ad1
docs(projects): explain project and workspace creation flows
mzxchandra a14b448
fix(projects): stage activation after compatible writers deploy
mzxchandra 5121347
feat(projects): enforce membership after the staged backfill
mzxchandra 523338a
fix(projects): retry writes after concurrent membership changes
mzxchandra dc5e301
fix(projects): align integration fixtures with membership constraints
mzxchandra c1c8e5d
refactor(projects): prepare compatible writers for the SQL backfill
mzxchandra 2e94a13
Merge branch 'feat/project-entity-foundation' into codex/project-enti…
mzxchandra 5e11d7d
refactor(projects): backfill through bounded SQL migration batches
mzxchandra 99189f2
fix(projects): clean up automatically created fixture Projects
mzxchandra 78f773d
Merge branch 'feat/project-entity-foundation' into codex/project-enti…
mzxchandra 2ecbfdf
fix(projects): backfill only families missing membership
mzxchandra 30bc9d8
chore(projects): merge staging into foundation
mzxchandra b5cc3c4
chore(projects): merge updated foundation into enforcement
mzxchandra 2afc652
fix(projects): bound the trigger installation lock window
mzxchandra 6dfbc4f
fix(workflows): guard restore against concurrent workspace archive
mzxchandra 8965210
fix(projects): keep workflow lifecycle guards at workspace scope
mzxchandra 552ce68
fix(workflows): guard restore against concurrent workspace archive
mzxchandra 8be18e5
Merge branch 'feat/project-entity-foundation' into codex/project-enti…
mzxchandra 0b7eed6
fix(projects): close lifecycle races and surface rollout conflicts
mzxchandra b8c44e9
Merge branch 'feat/project-entity-foundation' into codex/project-enti…
mzxchandra 634b19e
fix(workflows): return not found when import loses archive race
mzxchandra 40ea011
Merge branch 'feat/project-entity-foundation' into codex/project-enti…
mzxchandra fd874d0
fix(projects): tighten rollout checks and deduplicate lifecycle valid…
mzxchandra d3c56a0
test(projects): detect missing lifecycle validation calls
mzxchandra 8f36f2d
test(projects): verify concurrent lifecycle lock contention
mzxchandra 7ec83f0
chore(projects): merge staging into membership enforcement
mzxchandra ef5498a
test(projects): update new workspace fixtures for enforcement
mzxchandra 41b3a28
chore(projects): sync enforcement migrations with staging
mzxchandra 10a5f06
chore(projects): follow staging table migration
mzxchandra 28b0017
chore(projects): merge staging and advance enforcement migration
mzxchandra e2b8dfa
fix(tests): create Project membership in desktop and CLI fixtures
mzxchandra 3cf5483
Merge staging into project enforcement and advance migration to 0402
mzxchandra 947fda1
Merge pinned staging and advance Project enforcement to 0403
mzxchandra ab1e8cb
Merge pinned staging table ordering changes and provision dispatcher …
mzxchandra d4635ed
Merge pinned staging acquisition attribution changes
mzxchandra 83bdee2
fix(tests): restore Project enforcement fixtures after migration renu…
mzxchandra 61ffede
fix(tests): scope migration probes and align remaining Project fixtures
mzxchandra 4297631
refactor(projects): enforce membership through workspace project column
mzxchandra f781687
merge compatibility fixture validation into column enforcement
mzxchandra 363a0e1
Merge branch 'feat/project-workspace-column-expand' into codex/projec…
mzxchandra 744dd0d
Merge column-only Project membership and retire connector after rollout
mzxchandra 51ff1dc
Merge staging and order Project enforcement after column expansion
mzxchandra d782078
Merge Project transfer fixture corrections into enforcement
mzxchandra 1376167
test(projects): provision required membership in transfer unit fixtures
mzxchandra 0933be0
Merge workspace response projection from Project column expansion
mzxchandra 3e4c88c
feat(projects): prepare legacy membership with a resumable operator tool
mzxchandra c375ebc
Merge branch 'feat/project-workspace-column-expand' into codex/projec…
mzxchandra 243af21
Merge branch 'feat/project-workspace-column-expand' into codex/projec…
mzxchandra 786ac33
Merge branch 'feat/project-workspace-column-expand' into codex/projec…
mzxchandra c240b7f
Merge branch 'feat/project-workspace-column-expand' into codex/projec…
mzxchandra 39f54a0
fix(projects): support PostgreSQL 16 preparation and current fixtures
mzxchandra 6d4185b
Merge branch 'feat/project-workspace-column-expand' into codex/projec…
mzxchandra 8f06830
fix(projects): enforce safe schema push provisioning
mzxchandra 677186f
Merge branch 'feat/project-workspace-column-expand' into codex/projec…
mzxchandra c2b95cb
test(projects): provision newly merged workspace fixtures
mzxchandra 50361dc
Merge branch 'feat/project-workspace-column-expand' into codex/projec…
mzxchandra d1c7457
Merge branch 'feat/project-workspace-column-expand' into codex/projec…
mzxchandra 97a439e
Merge branch 'feat/project-workspace-column-expand' into codex/projec…
mzxchandra 7f8eb18
Merge branch 'feat/project-workspace-column-expand' into codex/projec…
mzxchandra b653f5e
fix(projects): close operator verification and contention gaps
mzxchandra 38d192d
test(billing): stabilize member ledger timeout checks
mzxchandra 8c3c334
fix(projects): await cleanup and bound backfill artifacts
mzxchandra 454e2e2
fix(projects): honor operator cancellation and status exits
mzxchandra fb27e1b
fix(projects): reject verification of conflicted plans
mzxchandra 88d10da
fix(projects): defer archive repair on database contention
mzxchandra 4025e5a
fix(projects): coordinate read-only maintenance commands
mzxchandra c5ff743
fix(projects): run bounded membership backfill before enforcement
mzxchandra 72da20a
Merge trigger-free expansion into project enforcement
mzxchandra 7613c14
test(projects): verify column-only archive repair assignment
mzxchandra 8e35470
Merge schema-push index fix into project enforcement
mzxchandra e92ba0b
ci(projects): use standard integration coverage for enforcement
mzxchandra bdf50b2
fix(projects): reconcile assigned environments before enforcement
mzxchandra ecfdf8b
chore(projects): integrate validated column expansion into enforcement
mzxchandra d9743bb
fix(projects): preserve backfill repair and resume guarantees
mzxchandra 639c8ca
test(projects): align fixture lifecycle with enforced project ownership
mzxchandra 1e4499e
fix(projects): integrate reviewed repair and fixture corrections
mzxchandra c704293
test(projects): skip archive repair suite when Redis is unset
mzxchandra b2718cb
merge: integrate renumbered Project expansion and staging fixtures
mzxchandra d0a9792
chore(projects): normalize enforcement SQL whitespace
mzxchandra d8a9627
feat(projects): commit membership authority before reconciliation
mzxchandra 32f49e3
merge: integrate Project authority switch into enforcement
mzxchandra 406a78f
merge: sync Project enforcement with expansion 0406
mzxchandra e5da5c8
merge: synchronize expansion fixture lint fix
mzxchandra d1443c8
merge: synchronize expansion billing fixture fix
mzxchandra 14554d0
Merge bounded authority barrier and replay review fixes
mzxchandra 357740a
fix(projects): pin operator schema and pace detach repairs
mzxchandra 69df502
Merge branch 'feat/project-workspace-column-expand' into codex/projec…
mzxchandra 36b0074
refactor(projects): replace integrity triggers with native foreign keys
mzxchandra d4e3da6
Merge branch 'feat/project-workspace-column-expand' into codex/projec…
mzxchandra d2f0893
fix(projects): retire rollout marker with legacy membership
mzxchandra File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| #!/usr/bin/env python3 | ||
| """Read-only, fail-closed ECS retirement check for the Project column contract migration. | ||
| The expected digest acknowledges fully deployed #8830 transaction-barrier and durable-authority support | ||
| and retirement of every incompatible server and relevant old worker job before switching. Every live and supported | ||
| rollback application must tolerate project_workspace being absent. | ||
| AWS checks below independently verify ECS retirement, not worker drainage. | ||
| """ | ||
| import argparse | ||
| import datetime | ||
| import json | ||
| import re | ||
| import subprocess | ||
| import sys | ||
|
|
||
|
|
||
| def aws(region, *args): | ||
| result = subprocess.run( | ||
| ['aws', '--region', region, '--no-cli-pager', '--cli-connect-timeout', '10', '--cli-read-timeout', '30', *args, '--output', 'json'], | ||
| capture_output=True, text=True, timeout=90, check=False, | ||
| ) | ||
| if result.returncode: | ||
| raise RuntimeError('AWS preflight read failed; check deployment-read permissions') | ||
| return json.loads(result.stdout) | ||
|
|
||
|
|
||
| def latest_execution(region, pipeline): | ||
| executions = aws(region, 'codepipeline', 'list-pipeline-executions', '--pipeline-name', pipeline).get('pipelineExecutionSummaries', []) | ||
| def epoch(execution): | ||
| value = execution['startTime'] | ||
| return value if isinstance(value, (int, float)) else datetime.datetime.fromisoformat(value.replace('Z', '+00:00')).timestamp() | ||
| if not executions: | ||
| raise RuntimeError('No application deployment execution was found') | ||
| return max(executions, key=epoch) | ||
|
|
||
|
|
||
| def matches_release(execution, digest): | ||
| return execution.get('status') == 'Succeeded' and any( | ||
| revision.get('actionName') == 'ECR_Source' and revision.get('revisionId') == digest | ||
| for revision in execution.get('sourceRevisions', []) | ||
| ) | ||
|
|
||
|
|
||
| def verify(environment, region, digest): | ||
| if not re.fullmatch(r'sha256:[0-9a-f]{64}', digest): | ||
| raise RuntimeError('Set the environment-specific PROJECT_COLUMN_ENFORCEMENT_READY_IMAGE_DIGEST after verifying #8830 authority-aware readers/writers, transaction barriers and all incompatible server/worker drainage') | ||
| pipeline = f'sim-{environment}-{region}-app-deployment' | ||
| execution = latest_execution(region, pipeline) | ||
| if not matches_release(execution, digest): | ||
| raise RuntimeError('The latest app pipeline has not completed for the acknowledged image; traffic cutover alone is insufficient') | ||
| execution_id = execution['pipelineExecutionId'] | ||
| group = aws(region, 'deploy', 'get-deployment-group', '--application-name', f'sim-{environment}-{region}-ecs-app', | ||
| '--deployment-group-name', f'sim-{environment}-{region}-app-dg')['deploymentGroupInfo'] | ||
| services = group.get('ecsServices', []) | ||
| if len(services) != 1: | ||
| raise RuntimeError('Expected exactly one application ECS service') | ||
| cluster, service = services[0]['clusterName'], services[0]['serviceName'] | ||
| description = aws(region, 'ecs', 'describe-services', '--cluster', cluster, '--services', service) | ||
| if description.get('failures') or len(description.get('services', [])) != 1: | ||
| raise RuntimeError('Cannot inspect the application ECS service') | ||
| record = description['services'][0] | ||
| if record.get('desiredCount', 0) < 1 or record.get('runningCount') != record['desiredCount'] or record.get('pendingCount') != 0: | ||
| raise RuntimeError('Application ECS service is not stable') | ||
| arns = set() | ||
| for status in ('RUNNING', 'STOPPED'): | ||
| arns.update(aws(region, 'ecs', 'list-tasks', '--cluster', cluster, '--service-name', service, | ||
| '--desired-status', status).get('taskArns', [])) | ||
| live = [] | ||
| ordered = sorted(arns) | ||
| for start in range(0, len(ordered), 100): | ||
| response = aws(region, 'ecs', 'describe-tasks', '--cluster', cluster, '--tasks', *ordered[start:start + 100]) | ||
| if response.get('failures'): | ||
| raise RuntimeError('Cannot account for every ECS task') | ||
| if len(response.get('tasks', [])) != len(ordered[start:start + 100]): | ||
| raise RuntimeError('Incomplete ECS task response') | ||
| live.extend(task for task in response['tasks'] if task.get('lastStatus') != 'STOPPED') | ||
| if len(live) != record['desiredCount']: | ||
| raise RuntimeError('Old, stopping, or pending ECS tasks remain') | ||
| for task in live: | ||
| app = [container for container in task.get('containers', []) if container.get('name') == 'app'] | ||
| if task.get('lastStatus') != 'RUNNING' or task.get('desiredStatus') != 'RUNNING' or len(app) != 1 or app[0].get('imageDigest') != digest: | ||
| raise RuntimeError('A live ECS task does not match the acknowledged compatible release') | ||
| latest = latest_execution(region, pipeline) | ||
| if latest.get('pipelineExecutionId') != execution_id or not matches_release(latest, digest): | ||
|
mzxchandra marked this conversation as resolved.
|
||
| raise RuntimeError('Application deployment changed during preflight') | ||
| print(json.dumps({'ecsRetired': True, 'expectedImageDigest': digest, 'pipelineExecutionId': execution_id, | ||
| 'operatorAcknowledgedColumnWritersAndWorkers': True})) | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| parser = argparse.ArgumentParser(description=__doc__) | ||
| parser.add_argument('--environment', required=True, choices=['production', 'staging']) | ||
| parser.add_argument('--region', required=True) | ||
| parser.add_argument('--expected-image-digest', required=True) | ||
| args = parser.parse_args() | ||
| try: | ||
| verify(args.environment, args.region, args.expected_image_digest) | ||
| except (RuntimeError, ValueError, KeyError, TypeError, subprocess.TimeoutExpired) as error: | ||
| print(f'Project column rollout preflight refused: {error}', file=sys.stderr) | ||
| sys.exit(1) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.