src-auth-perms-sync 0.7.0__tar.gz → 0.8.1__tar.gz
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.
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/.github/workflows/release.yml +2 -2
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/.github/workflows/validate.yml +10 -7
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/AGENTS.md +12 -13
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/PKG-INFO +26 -26
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/README.md +23 -23
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/dev/TODO.md +5 -5
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/dev/engineering-requests.md +10 -10
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/dev/memory-analysis/memory-efficiency-analyze.py +1 -1
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/examples/import.py +3 -3
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/examples/maps.yaml +2 -2
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/pyproject.toml +5 -7
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/cli.py +126 -99
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/orgs/sync.py +76 -13
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/permissions/apply.py +8 -8
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/permissions/command.py +41 -32
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/permissions/full_set.py +11 -11
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/permissions/mapping.py +16 -16
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/permissions/maps.py +93 -74
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/permissions/queries.py +3 -3
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/permissions/restore.py +9 -9
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/permissions/snapshot.py +9 -9
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/permissions/sourcegraph.py +10 -6
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/permissions/types.py +1 -1
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/permissions/workflow.py +4 -4
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/shared/backups.py +3 -3
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/shared/run_context.py +3 -3
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/shared/saml_groups.py +12 -11
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/shared/site_config.py +11 -11
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/shared/sourcegraph.py +1 -1
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/shared/types.py +1 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/README.md +23 -23
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/case_runner.py +17 -14
- src_auth_perms_sync-0.8.1/tests/e2e/fixtures/set-users-sync-saml-orgs-noop/after.json +114 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-sync-saml-orgs-scoped/after.json +1 -1
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/sync-saml-orgs-full-cleanup/after.json +1 -1
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/sync-saml-orgs-users-scoped/after.json +1 -1
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/test_local_cases.py +4 -4
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/integration/test_cli_entrypoint.py +8 -1
- src_auth_perms_sync-0.8.1/tests/live-maps-seed.yaml +80 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/run.py +463 -30
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/setup.py +220 -7
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/setup.yaml +4 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/tests.yaml +50 -46
- src_auth_perms_sync-0.8.1/tests/unicode_scan.py +65 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/unit/test_backups.py +3 -3
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/unit/test_cli_config.py +163 -30
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/unit/test_command_additive.py +2 -2
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/unit/test_command_files.py +16 -8
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/unit/test_maps.py +3 -2
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/unit/test_permissions_sourcegraph.py +2 -2
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/unit/test_restore.py +4 -4
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/unit/test_saml_groups.py +12 -6
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/unit/test_snapshot.py +1 -1
- src_auth_perms_sync-0.8.1/tests/unit/test_unicode_scan.py +22 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/uv.lock +50 -50
- src_auth_perms_sync-0.7.0/tests/confusables.py +0 -215
- src_auth_perms_sync-0.7.0/tests/unit/test_confusables.py +0 -35
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/.github/CODEOWNERS +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/.github/workflows/ci.yml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/.gitignore +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/.markdownlint-cli2.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/.python-version +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/LICENSE +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/SECURITY.md +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/dev/audit-dead-code.md +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/dev/hooks/pre-commit +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/dev/memory-analysis/mapping-efficiency.md +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/dev/memory-analysis/memory-efficiency-generate.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/dev/memory-analysis/memory-efficiency-monitor-sourcegraph.sh +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/dev/memory-analysis/memory-efficiency.md +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/dev/update-python-versions.md +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/package-lock.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/package.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/renovate.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/__init__.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/__main__.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/orgs/__init__.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/orgs/command.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/orgs/queries.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/orgs/types.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/permissions/__init__.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/shared/__init__.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/src/src_auth_perms_sync/shared/queries.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/__init__.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/__init__.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/add-users-by-email-and-list/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/add-users-by-email-and-list/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/add-users-by-email-and-list/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/add-users-preserves-existing/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/add-users-preserves-existing/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/add-users-preserves-existing/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/and-filters-intersect/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/and-filters-intersect/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/and-filters-intersect/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/empty-maps-noop/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/empty-maps-noop/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/full-overwrite-dry-run/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/full-overwrite-dry-run/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/full-overwrite-preserves-pending/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/full-overwrite-preserves-pending/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/full-overwrite-preserves-pending/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/full-overwrite-removes-stale-grant/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/full-overwrite-removes-stale-grant/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/full-overwrite-removes-stale-grant/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/full-overwrite-unions/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/full-overwrite-unions/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/full-overwrite-unions/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/full-overwrite-with-backup/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/full-overwrite-with-backup/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/full-overwrite-with-backup/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/get-full-snapshot/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/get-repos-without-explicit-perms/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/get-user-grants/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/invalid-bad-regex/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/invalid-bad-regex/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/invalid-missing-repos-section/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/invalid-missing-repos-section/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/invalid-restore-wrong-schema-version/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/invalid-restore-wrong-schema-version/snapshot.json +0 -0
- {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/invalid-set-created-after-date → src_auth_perms_sync-0.8.1/tests/e2e/fixtures/invalid-set-repos-created-after-date}/before.json +0 -0
- {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/invalid-set-created-after-date → src_auth_perms_sync-0.8.1/tests/e2e/fixtures/invalid-set-repos-created-after-date}/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/invalid-set-repos-created-after-date → src_auth_perms_sync-0.8.1/tests/e2e/fixtures/invalid-set-unknown-repo}/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/invalid-set-unknown-repo/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/invalid-set-unknown-repo → src_auth_perms_sync-0.8.1/tests/e2e/fixtures/invalid-set-unknown-user}/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/invalid-set-unknown-user/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/invalid-set-unknown-user → src_auth_perms_sync-0.8.1/tests/e2e/fixtures/invalid-set-users-created-after-date}/before.json +0 -0
- {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/invalid-set-repos-created-after-date → src_auth_perms_sync-0.8.1/tests/e2e/fixtures/invalid-set-users-created-after-date}/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/invalid-unknown-selector-field/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/invalid-unknown-selector-field/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/match-provider-and-host-fields/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/match-provider-and-host-fields/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/match-provider-and-host-fields/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/no-match-noop/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/no-match-noop/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/regex-filters-scope/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/regex-filters-scope/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/regex-filters-scope/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/restore-applies-snapshot/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/restore-applies-snapshot/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/restore-applies-snapshot/snapshot.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/restore-dry-run-noop/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/restore-dry-run-noop/snapshot.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/restore-missing-file/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/restore-restores-pending/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/restore-restores-pending/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/restore-restores-pending/snapshot.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/saml-group-filter/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/saml-group-filter/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/saml-group-filter/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/saml-group-live/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/saml-group-live/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/saml-group-live/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/set-created-after-sync-saml-orgs-dry-run → src_auth_perms_sync-0.8.1/tests/e2e/fixtures/set-full-sync-saml-orgs-dry-run}/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-repos-created-after/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-repos-created-after/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-repos-created-after/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-repos-created-after-noop/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-repos-created-after-noop/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/set-full-sync-saml-orgs-dry-run → src_auth_perms_sync-0.8.1/tests/e2e/fixtures/set-repos-created-after-sync-saml-orgs-dry-run}/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-repos-filter/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-repos-filter/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-repos-filter/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/set-repos-created-after-sync-saml-orgs-dry-run → src_auth_perms_sync-0.8.1/tests/e2e/fixtures/set-repos-sync-saml-orgs-dry-run}/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-repos-without-explicit-perms/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-repos-without-explicit-perms/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-repos-without-explicit-perms/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/set-repos-sync-saml-orgs-dry-run → src_auth_perms_sync-0.8.1/tests/e2e/fixtures/set-repos-without-perms-sync-saml-orgs-dry-run}/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-created-after/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-created-after/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-created-after/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-created-after-noop/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-created-after-noop/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/set-repos-without-perms-sync-saml-orgs-dry-run → src_auth_perms_sync-0.8.1/tests/e2e/fixtures/set-users-created-after-sync-saml-orgs-dry-run}/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/set-created-after-temp-user → src_auth_perms_sync-0.8.1/tests/e2e/fixtures/set-users-created-after-temp-user}/after.json +0 -0
- {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/set-created-after-temp-user → src_auth_perms_sync-0.8.1/tests/e2e/fixtures/set-users-created-after-temp-user}/before.json +0 -0
- {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/set-created-after-temp-user → src_auth_perms_sync-0.8.1/tests/e2e/fixtures/set-users-created-after-temp-user}/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-sync-saml-orgs-dry-run/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-sync-saml-orgs-noop/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-sync-saml-orgs-noop/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-sync-saml-orgs-scoped/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-sync-saml-orgs-scoped/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-without-explicit-perms/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-without-explicit-perms/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-without-explicit-perms/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-without-explicit-perms-default-batch/after.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-without-explicit-perms-default-batch/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-without-explicit-perms-default-batch/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/set-users-without-perms-sync-saml-orgs-dry-run/maps.yaml +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/sync-saml-orgs-full-cleanup/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/e2e/fixtures/sync-saml-orgs-users-scoped/before.json +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/integration/__init__.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/unit/__init__.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/unit/test_apply.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/unit/test_mapping_rules.py +0 -0
- {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.1}/tests/unit/test_module_api.py +0 -0
|
@@ -83,7 +83,7 @@ jobs:
|
|
|
83
83
|
|
|
84
84
|
steps:
|
|
85
85
|
- name: Check out release ref
|
|
86
|
-
uses: actions/checkout@
|
|
86
|
+
uses: actions/checkout@v7
|
|
87
87
|
with:
|
|
88
88
|
fetch-depth: 0
|
|
89
89
|
persist-credentials: false
|
|
@@ -95,7 +95,7 @@ jobs:
|
|
|
95
95
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
96
96
|
|
|
97
97
|
- name: Cache uv
|
|
98
|
-
uses: actions/cache@
|
|
98
|
+
uses: actions/cache@v6
|
|
99
99
|
with:
|
|
100
100
|
path: ~/.cache/uv
|
|
101
101
|
key: uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('uv.lock') }}
|
|
@@ -98,7 +98,7 @@ jobs:
|
|
|
98
98
|
|
|
99
99
|
steps:
|
|
100
100
|
- name: Check out code
|
|
101
|
-
uses: actions/checkout@
|
|
101
|
+
uses: actions/checkout@v7
|
|
102
102
|
with:
|
|
103
103
|
persist-credentials: false
|
|
104
104
|
ref: ${{ inputs.ref || github.ref }}
|
|
@@ -131,13 +131,13 @@ jobs:
|
|
|
131
131
|
|
|
132
132
|
steps:
|
|
133
133
|
- name: Check out code
|
|
134
|
-
uses: actions/checkout@
|
|
134
|
+
uses: actions/checkout@v7
|
|
135
135
|
with:
|
|
136
136
|
persist-credentials: false
|
|
137
137
|
ref: ${{ inputs.ref || github.ref }}
|
|
138
138
|
|
|
139
139
|
- name: Cache npm
|
|
140
|
-
uses: actions/cache@
|
|
140
|
+
uses: actions/cache@v6
|
|
141
141
|
with:
|
|
142
142
|
path: ~/.npm
|
|
143
143
|
key: npm-${{ runner.os }}-markdownlint-cli2-${{ env.MARKDOWNLINT_CLI2_VERSION }}-relative-links-${{ env.MARKDOWNLINT_RELATIVE_LINKS_VERSION }}
|
|
@@ -160,7 +160,7 @@ jobs:
|
|
|
160
160
|
|
|
161
161
|
steps:
|
|
162
162
|
- name: Check out code
|
|
163
|
-
uses: actions/checkout@
|
|
163
|
+
uses: actions/checkout@v7
|
|
164
164
|
with:
|
|
165
165
|
fetch-depth: 0
|
|
166
166
|
persist-credentials: false
|
|
@@ -172,7 +172,7 @@ jobs:
|
|
|
172
172
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
173
173
|
|
|
174
174
|
- name: Cache uv
|
|
175
|
-
uses: actions/cache@
|
|
175
|
+
uses: actions/cache@v6
|
|
176
176
|
with:
|
|
177
177
|
path: ~/.cache/uv
|
|
178
178
|
key: uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('uv.lock') }}
|
|
@@ -185,6 +185,9 @@ jobs:
|
|
|
185
185
|
- name: Validate lockfile
|
|
186
186
|
run: uv lock --check
|
|
187
187
|
|
|
188
|
+
- name: Scan for Unicode characters
|
|
189
|
+
run: uv run --frozen python tests/unicode_scan.py
|
|
190
|
+
|
|
188
191
|
- name: Lint Python
|
|
189
192
|
run: uv run --frozen ruff check .
|
|
190
193
|
|
|
@@ -212,7 +215,7 @@ jobs:
|
|
|
212
215
|
|
|
213
216
|
steps:
|
|
214
217
|
- name: Check out code
|
|
215
|
-
uses: actions/checkout@
|
|
218
|
+
uses: actions/checkout@v7
|
|
216
219
|
with:
|
|
217
220
|
fetch-depth: 0
|
|
218
221
|
persist-credentials: false
|
|
@@ -224,7 +227,7 @@ jobs:
|
|
|
224
227
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
225
228
|
|
|
226
229
|
- name: Cache uv
|
|
227
|
-
uses: actions/cache@
|
|
230
|
+
uses: actions/cache@v6
|
|
228
231
|
with:
|
|
229
232
|
path: ~/.cache/uv
|
|
230
233
|
key: uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('uv.lock') }}
|
|
@@ -14,9 +14,8 @@ actionlint
|
|
|
14
14
|
### Markdown files
|
|
15
15
|
npx --yes -p markdownlint-cli2@0.22.1 -p markdownlint-rule-relative-links@5.1.0 markdownlint-cli2
|
|
16
16
|
|
|
17
|
-
###
|
|
18
|
-
|
|
19
|
-
uv run python tests/confusables.py
|
|
17
|
+
### Non-ASCII characters in tracked text files
|
|
18
|
+
uv run python tests/unicode_scan.py
|
|
20
19
|
|
|
21
20
|
### Python files
|
|
22
21
|
|
|
@@ -41,7 +40,7 @@ own checks.
|
|
|
41
40
|
|
|
42
41
|
```bash
|
|
43
42
|
# Fast, no network (also what the pre-commit hook runs):
|
|
44
|
-
# lint, format, pyright,
|
|
43
|
+
# lint, format, pyright, non-ASCII character scan, unit + fixture
|
|
45
44
|
# tests, CLI rejection matrix,
|
|
46
45
|
# randomized permission invariants
|
|
47
46
|
uv run tests/run.py
|
|
@@ -64,7 +63,7 @@ uv run tests/run.py --performance --baseline-command "uvx src-auth-perms-sync@la
|
|
|
64
63
|
uv run tests/run.py --update-golden
|
|
65
64
|
```
|
|
66
65
|
|
|
67
|
-
- Fixture cases live in `tests/e2e/fixtures/<case>/`
|
|
66
|
+
- Fixture cases live in `tests/e2e/fixtures/<case>/` - see the README there
|
|
68
67
|
for the format. Add cases there to cover new mapping behaviors.
|
|
69
68
|
- For manual verification against a real instance, dry-run first (no
|
|
70
69
|
`--apply`), read the planned changes, then `--apply` on a scratch instance
|
|
@@ -165,7 +164,7 @@ gh run watch "${RUN_ID}" --repo "${GH_REPO}" --exit-status
|
|
|
165
164
|
gh release view "v${VERSION}" --repo "${GH_REPO}"
|
|
166
165
|
```
|
|
167
166
|
|
|
168
|
-
## Hard invariants
|
|
167
|
+
## Hard invariants - do not break
|
|
169
168
|
|
|
170
169
|
Violating these can silently grant the wrong users access to the wrong
|
|
171
170
|
repos.
|
|
@@ -206,31 +205,31 @@ organization sync maps SAML groups to Sourcegraph org membership. Read
|
|
|
206
205
|
CLI lives in `src/src_auth_perms_sync/`; invoke with `uv run src-auth-perms-sync`.
|
|
207
206
|
Strict pyright covers the package. Root modules are entrypoints only:
|
|
208
207
|
|
|
209
|
-
- `cli.py`
|
|
208
|
+
- `cli.py` - `main()`, arg parsing, owns the CLI description. Module
|
|
210
209
|
wrappers (`Get`/`Set`/`Restore`/`SyncSamlOrgs`) return result dataclasses
|
|
211
210
|
and never install logging handlers; only `main()` runs CLI-mode logging.
|
|
212
|
-
- `shared/`
|
|
211
|
+
- `shared/` - cross-workflow helpers: Sourcegraph auth-provider/user list
|
|
213
212
|
helpers, shared GraphQL operations and TypedDicts, site-config validation,
|
|
214
213
|
and SAML group parsing. `shared/backups.py` defines `RunPaths`: every
|
|
215
214
|
filesystem path for one run, resolved once at the edge
|
|
216
|
-
(`resolve_run_paths`) and threaded explicitly
|
|
215
|
+
(`resolve_run_paths`) and threaded explicitly - never recompute paths
|
|
217
216
|
from cwd or globals below the edge, and honor `run_paths.write_files`
|
|
218
217
|
(False under `--no-files`) before any disk write.
|
|
219
218
|
|
|
220
219
|
Business workflows live in packages:
|
|
221
220
|
|
|
222
|
-
- `permissions/`
|
|
221
|
+
- `permissions/` - repo permission sync (`command.py`, `maps.py`,
|
|
223
222
|
`mapping.py`, `sourcegraph.py`, `snapshot.py`, `apply.py`, `queries.py`,
|
|
224
223
|
`types.py`). Add new mapping filters in `permissions/types.py` and
|
|
225
224
|
`permissions/mapping.py`.
|
|
226
|
-
- `orgs/`
|
|
225
|
+
- `orgs/` - SAML group -> Sourcegraph organization sync (`command.py`,
|
|
227
226
|
`queries.py`, `types.py`).
|
|
228
227
|
|
|
229
228
|
## Toolchain
|
|
230
229
|
|
|
231
230
|
- Python 3.11 + [uv](https://docs.astral.sh/uv/). Never invoke `python`
|
|
232
231
|
directly; always `uv run ...`.
|
|
233
|
-
- `uv run pyright` must be clean. No `# type: ignore` to silence
|
|
232
|
+
- `uv run pyright` must be clean. No `# type: ignore` to silence -
|
|
234
233
|
fix the underlying type.
|
|
235
234
|
- Local tests use stdlib `unittest`: `uv run python -m unittest discover -s tests`.
|
|
236
235
|
- For Sourcegraph mutation-path changes, also verify by dry-running `--get` /
|
|
@@ -268,7 +267,7 @@ Short names that ARE acceptable (don't rewrite these on sight):
|
|
|
268
267
|
`key`, `value`, `name`, `kind`.
|
|
269
268
|
- **Stdlib idioms**: `ctx` for `contextvars.copy_context()`.
|
|
270
269
|
- **Loop / comprehension variables when the type is obvious from one
|
|
271
|
-
line of context** is still discouraged
|
|
270
|
+
line of context** is still discouraged - prefer `user`, `repo`,
|
|
272
271
|
`provider`, `service`, `permission`, `node`, `entry`, `match`,
|
|
273
272
|
`account`, `future`, `executor`, `exception`, `event`, `connection`,
|
|
274
273
|
`response`, `timestamp`, `current`, `outcome`, `index`, `field_name`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: src-auth-perms-sync
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.1
|
|
4
4
|
Summary: Set Sourcegraph permissions from authentication provider data
|
|
5
5
|
Project-URL: Homepage, https://github.com/sourcegraph/src-auth-perms-sync
|
|
6
6
|
Project-URL: Issues, https://github.com/sourcegraph/src-auth-perms-sync/issues
|
|
@@ -16,13 +16,13 @@ Classifier: Operating System :: OS Independent
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
17
|
Classifier: Typing :: Typed
|
|
18
18
|
Requires-Python: >=3.11
|
|
19
|
-
Requires-Dist: json5>=0.
|
|
19
|
+
Requires-Dist: json5>=0.15.0
|
|
20
20
|
Requires-Dist: pyyaml>=6.0.3
|
|
21
|
-
Requires-Dist: src-py-lib[otel]==0.3.
|
|
21
|
+
Requires-Dist: src-py-lib[otel]==0.3.2
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
23
23
|
|
|
24
24
|
# src-auth-perms-sync
|
|
25
|
-
<!-- HUMAN-MAINTAINED SECTION START
|
|
25
|
+
<!-- HUMAN-MAINTAINED SECTION START - DO NOT EDIT THIS SECTION -->
|
|
26
26
|
|
|
27
27
|
src-auth-perms-sync automates Sourcegraph's Explicit Permissions GraphQL API,
|
|
28
28
|
setting user-to-repo permissions based on mapping rules, for example:
|
|
@@ -167,10 +167,10 @@ result = src.Set(config) # truthy on success; result.paths has run artifacts
|
|
|
167
167
|
get_result = src.Get(config)
|
|
168
168
|
for provider in get_result.auth_providers:
|
|
169
169
|
...
|
|
170
|
-
for
|
|
170
|
+
for code_host_connection in get_result.code_host_connections:
|
|
171
171
|
...
|
|
172
172
|
|
|
173
|
-
# Mapping rules can be passed in memory instead of a maps YAML file
|
|
173
|
+
# Mapping rules can be passed in memory instead of a maps YAML file -
|
|
174
174
|
# same structure and validation as maps.yaml entries:
|
|
175
175
|
rules: list[src.MappingRule] = [
|
|
176
176
|
{
|
|
@@ -190,11 +190,11 @@ result = src.Set(config, mapping_rules=rules)
|
|
|
190
190
|
```
|
|
191
191
|
|
|
192
192
|
The import API does not read environment variables or `.env` files on its
|
|
193
|
-
own
|
|
193
|
+
own - those apply to the CLI only. Pass every value explicitly to
|
|
194
194
|
`src.Config(...)` (read `os.environ` yourself if you want env-driven
|
|
195
195
|
configuration, as the example above does).
|
|
196
196
|
|
|
197
|
-
Module mode never touches your `logging` handlers or the root logger
|
|
197
|
+
Module mode never touches your `logging` handlers or the root logger - your
|
|
198
198
|
application's logging config stays in charge. To see progress messages:
|
|
199
199
|
|
|
200
200
|
```python
|
|
@@ -248,7 +248,7 @@ snapshots that make `--apply` reversible.
|
|
|
248
248
|
```
|
|
249
249
|
|
|
250
250
|
- Queries the Sourcegraph instance for auth providers and code host connections
|
|
251
|
-
- Writes generated reference files `auth-providers.yaml` and `code-
|
|
251
|
+
- Writes generated reference files `auth-providers.yaml` and `code-host-connections.yaml` under
|
|
252
252
|
`src-auth-perms-sync-runs/<src_endpoint>/`
|
|
253
253
|
- Creates an empty `maps.yaml` if it doesn't exist
|
|
254
254
|
|
|
@@ -316,11 +316,11 @@ snapshots that make `--apply` reversible.
|
|
|
316
316
|
|
|
317
317
|
```bash
|
|
318
318
|
src-auth-perms-sync sync-saml-orgs --users alice,bob
|
|
319
|
-
src-auth-perms-sync sync-saml-orgs --created-after 2026-06-01
|
|
319
|
+
src-auth-perms-sync sync-saml-orgs --users-created-after 2026-06-01
|
|
320
320
|
src-auth-perms-sync sync-saml-orgs --users-without-explicit-perms
|
|
321
321
|
```
|
|
322
322
|
|
|
323
|
-
- Same user filters as `get` and `set`; a mode flag is required
|
|
323
|
+
- Same user filters as `get` and `set`; a mode flag is required - there
|
|
324
324
|
is no bare `sync-saml-orgs`
|
|
325
325
|
|
|
326
326
|
### Org sync behavior
|
|
@@ -328,14 +328,14 @@ snapshots that make `--apply` reversible.
|
|
|
328
328
|
- Org names are `synced-<configID>-<group name>` (non-alphanumeric characters
|
|
329
329
|
become `-`). The `synced-` prefix marks tool ownership: the sync only ever
|
|
330
330
|
modifies orgs whose name carries it, so manually created orgs are never touched.
|
|
331
|
-
- The org sync mode is always explicit
|
|
331
|
+
- The org sync mode is always explicit - no surprises:
|
|
332
332
|
- **Full** (`sync-saml-orgs --full`, or `set --full` / `--repos*`
|
|
333
333
|
`--sync-saml-orgs`): converges every synced org against all users. A synced
|
|
334
334
|
org whose SAML group disappeared has all members removed, but the org itself
|
|
335
335
|
is kept (its settings survive in case the group comes back).
|
|
336
336
|
- **Scoped** (user filters on `sync-saml-orgs`, or `set --users` /
|
|
337
|
-
`--users-without-explicit-perms` / `--created-after` with
|
|
338
|
-
`--sync-saml-orgs`): syncs org membership for exactly the selected users
|
|
337
|
+
`--users-without-explicit-perms` / `--users-created-after` with
|
|
338
|
+
`--sync-saml-orgs`): syncs org membership for exactly the selected users -
|
|
339
339
|
per-user additions AND removals, computed from each user's own SAML
|
|
340
340
|
assertion and org list. Other users' memberships never change, and no full
|
|
341
341
|
user scan or org member listing is needed, so API traffic stays
|
|
@@ -349,22 +349,22 @@ Run `src-auth-perms-sync --help` for options
|
|
|
349
349
|
|
|
350
350
|
```text
|
|
351
351
|
src-auth-perms-sync-runs/<src_endpoint>/
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
352
|
+
|-- auth-providers.yaml
|
|
353
|
+
|-- code-host-connections.yaml
|
|
354
|
+
|-- maps.yaml
|
|
355
|
+
`-- runs
|
|
356
|
+
`-- timestamp-command
|
|
357
|
+
|-- before.json
|
|
358
|
+
|-- after.json
|
|
359
|
+
|-- diff.json
|
|
360
|
+
|-- log.json
|
|
361
|
+
`-- maps.yaml
|
|
362
362
|
```
|
|
363
363
|
|
|
364
364
|
- The `src-auth-perms-sync-runs` dir is created under your current working directory
|
|
365
365
|
- The `<src_endpoint>` dir is created with the hostname from `SRC_ENDPOINT`
|
|
366
366
|
- If `maps.yaml` doesn't exist already, it'll be created for you
|
|
367
|
-
- `auth-providers.yaml` and `code-
|
|
367
|
+
- `auth-providers.yaml` and `code-host-connections.yaml` are created / replaced by the `get` command,
|
|
368
368
|
for you to copy values from, to use in your `maps.yaml`
|
|
369
369
|
- Only one `maps.yaml` file can be used at a time per Sourcegraph instance, as each `set --apply`
|
|
370
370
|
command resets the state on the Sourcegraph instance to the `maps.yaml` file which was used
|
|
@@ -376,4 +376,4 @@ src-auth-perms-sync-runs/<src_endpoint>/
|
|
|
376
376
|
- An `after.json` file, capturing the new state
|
|
377
377
|
- A `diff.json` file, a shorter, reviewable file containing the diffs between before and after
|
|
378
378
|
|
|
379
|
-
<!-- HUMAN-MAINTAINED SECTION END
|
|
379
|
+
<!-- HUMAN-MAINTAINED SECTION END - DO NOT EDIT ABOVE -->
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# src-auth-perms-sync
|
|
2
|
-
<!-- HUMAN-MAINTAINED SECTION START
|
|
2
|
+
<!-- HUMAN-MAINTAINED SECTION START - DO NOT EDIT THIS SECTION -->
|
|
3
3
|
|
|
4
4
|
src-auth-perms-sync automates Sourcegraph's Explicit Permissions GraphQL API,
|
|
5
5
|
setting user-to-repo permissions based on mapping rules, for example:
|
|
@@ -144,10 +144,10 @@ result = src.Set(config) # truthy on success; result.paths has run artifacts
|
|
|
144
144
|
get_result = src.Get(config)
|
|
145
145
|
for provider in get_result.auth_providers:
|
|
146
146
|
...
|
|
147
|
-
for
|
|
147
|
+
for code_host_connection in get_result.code_host_connections:
|
|
148
148
|
...
|
|
149
149
|
|
|
150
|
-
# Mapping rules can be passed in memory instead of a maps YAML file
|
|
150
|
+
# Mapping rules can be passed in memory instead of a maps YAML file -
|
|
151
151
|
# same structure and validation as maps.yaml entries:
|
|
152
152
|
rules: list[src.MappingRule] = [
|
|
153
153
|
{
|
|
@@ -167,11 +167,11 @@ result = src.Set(config, mapping_rules=rules)
|
|
|
167
167
|
```
|
|
168
168
|
|
|
169
169
|
The import API does not read environment variables or `.env` files on its
|
|
170
|
-
own
|
|
170
|
+
own - those apply to the CLI only. Pass every value explicitly to
|
|
171
171
|
`src.Config(...)` (read `os.environ` yourself if you want env-driven
|
|
172
172
|
configuration, as the example above does).
|
|
173
173
|
|
|
174
|
-
Module mode never touches your `logging` handlers or the root logger
|
|
174
|
+
Module mode never touches your `logging` handlers or the root logger - your
|
|
175
175
|
application's logging config stays in charge. To see progress messages:
|
|
176
176
|
|
|
177
177
|
```python
|
|
@@ -225,7 +225,7 @@ snapshots that make `--apply` reversible.
|
|
|
225
225
|
```
|
|
226
226
|
|
|
227
227
|
- Queries the Sourcegraph instance for auth providers and code host connections
|
|
228
|
-
- Writes generated reference files `auth-providers.yaml` and `code-
|
|
228
|
+
- Writes generated reference files `auth-providers.yaml` and `code-host-connections.yaml` under
|
|
229
229
|
`src-auth-perms-sync-runs/<src_endpoint>/`
|
|
230
230
|
- Creates an empty `maps.yaml` if it doesn't exist
|
|
231
231
|
|
|
@@ -293,11 +293,11 @@ snapshots that make `--apply` reversible.
|
|
|
293
293
|
|
|
294
294
|
```bash
|
|
295
295
|
src-auth-perms-sync sync-saml-orgs --users alice,bob
|
|
296
|
-
src-auth-perms-sync sync-saml-orgs --created-after 2026-06-01
|
|
296
|
+
src-auth-perms-sync sync-saml-orgs --users-created-after 2026-06-01
|
|
297
297
|
src-auth-perms-sync sync-saml-orgs --users-without-explicit-perms
|
|
298
298
|
```
|
|
299
299
|
|
|
300
|
-
- Same user filters as `get` and `set`; a mode flag is required
|
|
300
|
+
- Same user filters as `get` and `set`; a mode flag is required - there
|
|
301
301
|
is no bare `sync-saml-orgs`
|
|
302
302
|
|
|
303
303
|
### Org sync behavior
|
|
@@ -305,14 +305,14 @@ snapshots that make `--apply` reversible.
|
|
|
305
305
|
- Org names are `synced-<configID>-<group name>` (non-alphanumeric characters
|
|
306
306
|
become `-`). The `synced-` prefix marks tool ownership: the sync only ever
|
|
307
307
|
modifies orgs whose name carries it, so manually created orgs are never touched.
|
|
308
|
-
- The org sync mode is always explicit
|
|
308
|
+
- The org sync mode is always explicit - no surprises:
|
|
309
309
|
- **Full** (`sync-saml-orgs --full`, or `set --full` / `--repos*`
|
|
310
310
|
`--sync-saml-orgs`): converges every synced org against all users. A synced
|
|
311
311
|
org whose SAML group disappeared has all members removed, but the org itself
|
|
312
312
|
is kept (its settings survive in case the group comes back).
|
|
313
313
|
- **Scoped** (user filters on `sync-saml-orgs`, or `set --users` /
|
|
314
|
-
`--users-without-explicit-perms` / `--created-after` with
|
|
315
|
-
`--sync-saml-orgs`): syncs org membership for exactly the selected users
|
|
314
|
+
`--users-without-explicit-perms` / `--users-created-after` with
|
|
315
|
+
`--sync-saml-orgs`): syncs org membership for exactly the selected users -
|
|
316
316
|
per-user additions AND removals, computed from each user's own SAML
|
|
317
317
|
assertion and org list. Other users' memberships never change, and no full
|
|
318
318
|
user scan or org member listing is needed, so API traffic stays
|
|
@@ -326,22 +326,22 @@ Run `src-auth-perms-sync --help` for options
|
|
|
326
326
|
|
|
327
327
|
```text
|
|
328
328
|
src-auth-perms-sync-runs/<src_endpoint>/
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
329
|
+
|-- auth-providers.yaml
|
|
330
|
+
|-- code-host-connections.yaml
|
|
331
|
+
|-- maps.yaml
|
|
332
|
+
`-- runs
|
|
333
|
+
`-- timestamp-command
|
|
334
|
+
|-- before.json
|
|
335
|
+
|-- after.json
|
|
336
|
+
|-- diff.json
|
|
337
|
+
|-- log.json
|
|
338
|
+
`-- maps.yaml
|
|
339
339
|
```
|
|
340
340
|
|
|
341
341
|
- The `src-auth-perms-sync-runs` dir is created under your current working directory
|
|
342
342
|
- The `<src_endpoint>` dir is created with the hostname from `SRC_ENDPOINT`
|
|
343
343
|
- If `maps.yaml` doesn't exist already, it'll be created for you
|
|
344
|
-
- `auth-providers.yaml` and `code-
|
|
344
|
+
- `auth-providers.yaml` and `code-host-connections.yaml` are created / replaced by the `get` command,
|
|
345
345
|
for you to copy values from, to use in your `maps.yaml`
|
|
346
346
|
- Only one `maps.yaml` file can be used at a time per Sourcegraph instance, as each `set --apply`
|
|
347
347
|
command resets the state on the Sourcegraph instance to the `maps.yaml` file which was used
|
|
@@ -353,4 +353,4 @@ src-auth-perms-sync-runs/<src_endpoint>/
|
|
|
353
353
|
- An `after.json` file, capturing the new state
|
|
354
354
|
- A `diff.json` file, a shorter, reviewable file containing the diffs between before and after
|
|
355
355
|
|
|
356
|
-
<!-- HUMAN-MAINTAINED SECTION END
|
|
356
|
+
<!-- HUMAN-MAINTAINED SECTION END - DO NOT EDIT ABOVE -->
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
- `get --repos <name>` still scans every user's explicit grants to find one
|
|
33
33
|
repo's holders (~400 s at 10k users). A repo-centric read
|
|
34
34
|
(`repository.permissionsInfo.users` + site-admin disambiguation, as the
|
|
35
|
-
test harness already does) would make it seconds
|
|
35
|
+
test harness already does) would make it seconds - see the repo-centric
|
|
36
36
|
section below.
|
|
37
37
|
|
|
38
38
|
## Low priority: Repo-centric path, when users > repos, or for cross-checking
|
|
@@ -50,10 +50,10 @@ Reasons we might want to bring it back later:
|
|
|
50
50
|
- **Targeted snapshots.** A "planned-scope" capture (only the repos
|
|
51
51
|
the mapping rules touch) is faster than a full instance scan when
|
|
52
52
|
the user-centric path is the long pole AND the planned set is small.
|
|
53
|
-
Would need either a server-side `source` filter on the repo
|
|
53
|
+
Would need either a server-side `source` filter on the repo->users
|
|
54
54
|
connection, or a follow-up user-centric `source: API` query per
|
|
55
55
|
ambiguous (site-admin) user to disambiguate.
|
|
56
|
-
- **Adaptive capture path after SG adds `source` to repo
|
|
56
|
+
- **Adaptive capture path after SG adds `source` to repo->users.** Once
|
|
57
57
|
`RepositoryPermissionsInfo.users(source: PermissionSource)` exists,
|
|
58
58
|
compute the expected request count both ways before snapshotting:
|
|
59
59
|
sum `userCount` across all auth providers and sum `repoCount` across
|
|
@@ -70,7 +70,7 @@ If/when we revisit:
|
|
|
70
70
|
ambiguous-user follow-up to be correct).
|
|
71
71
|
2. Restore `QUERY_REPO_EXPLICIT_USERS` from git history; implement
|
|
72
72
|
`list_repo_explicit_users` returning `(definitely, ambiguous)` and
|
|
73
|
-
actually consume both buckets
|
|
73
|
+
actually consume both buckets - the previous code did neither.
|
|
74
74
|
3. Add a CLI flag (e.g. `--cross-check-capture`) gated behind a clear
|
|
75
75
|
"this doubles capture cost" warning.
|
|
76
76
|
|
|
@@ -89,7 +89,7 @@ SAML actually persists the group list. Recovery options for each:
|
|
|
89
89
|
- OIDC has no `allowGroups` field on `OpenIDConnectAuthProvider`.
|
|
90
90
|
`UserClaims` stores only name/email fields; the `groups` claim is never
|
|
91
91
|
parsed. Recovery needs an upstream change to persist the claim.
|
|
92
|
-
- GitHub OAuth has `allowOrgs`, `allowOrgsMap` (org
|
|
92
|
+
- GitHub OAuth has `allowOrgs`, `allowOrgsMap` (org->teams), and
|
|
93
93
|
`requiredSsoOrgs`. Org/team checks happen live in `verifyUserOrgs` /
|
|
94
94
|
`verifyUserTeams` and are discarded. Recovery needs an upstream change to
|
|
95
95
|
persist the claim.
|
|
@@ -88,15 +88,15 @@ Observed during the concurrent captures:
|
|
|
88
88
|
- `pgsql-0` CPU (`kubectl top`): 7,636-7,683 millicores of 8,000 (saturated).
|
|
89
89
|
- `frontend` / `gitserver` CPU: 124-138m / 2-3m (idle bystanders).
|
|
90
90
|
- `pg_stat_activity`: 29 active statements, all
|
|
91
|
-
`permsStore.ListUserPermissions`, **zero wait events**
|
|
91
|
+
`permsStore.ListUserPermissions`, **zero wait events** - pure CPU, no lock
|
|
92
92
|
contention.
|
|
93
93
|
- `pg_stat_statements`: `permsStore.ListUserPermissions` at 24,026 calls,
|
|
94
94
|
27,635.6s total, 1,150ms mean.
|
|
95
|
-
- Per-client capture throughput: 23 users/sec solo
|
|
95
|
+
- Per-client capture throughput: 23 users/sec solo -> 2-4 users/sec at 4-way
|
|
96
96
|
concurrency.
|
|
97
|
-
- Aggregate throughput: 8-16 users/sec at 4-way
|
|
97
|
+
- Aggregate throughput: 8-16 users/sec at 4-way - **below the 23 users/sec a
|
|
98
98
|
single client achieves alone** (negative scaling).
|
|
99
|
-
- ALB (CloudWatch): no 5xx, no rejected connections
|
|
99
|
+
- ALB (CloudWatch): no 5xx, no rejected connections - the edge and frontend
|
|
100
100
|
are not the bottleneck.
|
|
101
101
|
- Collateral failure: the fifth client's queries exceeded the 60s read timeout
|
|
102
102
|
under this load; 5 retry attempts exhausted; its run failed with exit 1.
|
|
@@ -144,7 +144,7 @@ from `github.com/sourcegraph/sourcegraph`:
|
|
|
144
144
|
Measured on the 10k-user / 50k-repo test instance, the presence probe
|
|
145
145
|
`User.permissionsInfo.repositories(source: API, first: 1)` costs 225-350ms of
|
|
146
146
|
server work per user, and alias batching barely helps (21,004 single-user
|
|
147
|
-
probes averaged 351.6ms; 25-user batches averaged 5,616ms
|
|
147
|
+
probes averaged 351.6ms; 25-user batches averaged 5,616ms ~ 224.7ms/user). A
|
|
148
148
|
single `set --users-without-explicit-perms` run probing all 10,002 users at
|
|
149
149
|
batch size 1 spent 4,269s of its 5,210s total in these probes.
|
|
150
150
|
|
|
@@ -158,9 +158,9 @@ Reading the resolver code in `github.com/sourcegraph/sourcegraph` explains why
|
|
|
158
158
|
`updatedAt` fields. The rows are discarded afterward.
|
|
159
159
|
- `userPermissionsInfoResolver.Repositories` (permissions_info.go) builds a
|
|
160
160
|
CTE (`reposPermissionsInfoQueryFmt` in perms_store.go) that **materializes
|
|
161
|
-
every repo accessible to the user**
|
|
162
|
-
`external_service_repos`
|
|
163
|
-
authz `EXISTS` predicate and an `ORDER BY`
|
|
161
|
+
every repo accessible to the user** - a full `repo` join
|
|
162
|
+
`external_service_repos` join `external_services` join with the correlated
|
|
163
|
+
authz `EXISTS` predicate and an `ORDER BY` - before the outer query applies
|
|
164
164
|
`urp.source = 'API'` and the LIMIT. `first: 1` becomes `LIMIT 2` on the
|
|
165
165
|
outer query only; the CTE is not short-circuited.
|
|
166
166
|
- Requesting `totalCount` adds a second independent execution of the same CTE
|
|
@@ -180,7 +180,7 @@ Client-side mitigation shipped in `src-auth-perms-sync` (2026-06-12):
|
|
|
180
180
|
locally BEFORE probing, so probes scale with the rule-matched user count
|
|
181
181
|
instead of the instance's user count, and user hydration runs as aliased
|
|
182
182
|
25-user batches instead of one `UserByID` request per user. The remaining
|
|
183
|
-
inherent cost
|
|
183
|
+
inherent cost - ~225ms x probed user - is exactly what the
|
|
184
184
|
presence/filter API requested below would remove, and
|
|
185
185
|
`get --users-without-explicit-perms` still has to probe every active user
|
|
186
186
|
because its semantics are instance-wide.
|
|
@@ -505,7 +505,7 @@ joined to `users` and `repo` for names.
|
|
|
505
505
|
|
|
506
506
|
### `GetPermissionSyncDiscovery`
|
|
507
507
|
|
|
508
|
-
The `get` command writes `code-
|
|
508
|
+
The `get` command writes `code-host-connections.yaml` and `auth-providers.yaml`, then uses
|
|
509
509
|
the same discovery data for mapping. A single discovery endpoint would simplify
|
|
510
510
|
this and avoid multiple round trips.
|
|
511
511
|
|
|
@@ -470,7 +470,7 @@ def write_text_report(
|
|
|
470
470
|
)
|
|
471
471
|
r_squared = "n/a" if model.r_squared is None else f"{model.r_squared:.4f}"
|
|
472
472
|
print("\nFit quality:")
|
|
473
|
-
print(f" R
|
|
473
|
+
print(f" R^2: {r_squared}")
|
|
474
474
|
print(f" mean absolute error: {model.mean_absolute_error_megabytes:.2f} MiB")
|
|
475
475
|
print(f" p95 absolute error: {model.p95_absolute_error_megabytes:.2f} MiB")
|
|
476
476
|
print(f" max absolute error: {model.max_absolute_error_megabytes:.2f} MiB")
|
|
@@ -27,9 +27,9 @@ config = src.Config(
|
|
|
27
27
|
# Discover the instance's auth providers and code hosts
|
|
28
28
|
discovery = src.Get(config)
|
|
29
29
|
for auth_provider in discovery.auth_providers:
|
|
30
|
-
print("auth provider:", auth_provider.get("displayName"))
|
|
31
|
-
for
|
|
32
|
-
print("code host:",
|
|
30
|
+
print("auth provider:", auth_provider["authProvider"].get("displayName"))
|
|
31
|
+
for code_host_connection in discovery.code_host_connections:
|
|
32
|
+
print("code host:", code_host_connection["codeHostConnection"].get("displayName"))
|
|
33
33
|
|
|
34
34
|
# Configure your mapping rules
|
|
35
35
|
mapping_rules: list[src.MappingRule] = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# User
|
|
1
|
+
# User -> Repo permission mapping rules
|
|
2
2
|
|
|
3
|
-
# Maintain your maps.yaml file, using the values from auth-providers.yaml and code-
|
|
3
|
+
# Maintain your maps.yaml file, using the values from auth-providers.yaml and code-host-connections.yaml,
|
|
4
4
|
# which are created by the --get command, under `src-auth-perms-sync-runs/<endpoint>/`
|
|
5
5
|
|
|
6
6
|
# Schema details:
|
|
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[dependency-groups]
|
|
6
6
|
dev = [
|
|
7
|
-
"pyright>=1.1.
|
|
8
|
-
"ruff>=0.15.
|
|
7
|
+
"pyright>=1.1.411",
|
|
8
|
+
"ruff>=0.15.20",
|
|
9
9
|
"types-pyyaml>=6.0.12.20260518",
|
|
10
10
|
]
|
|
11
11
|
|
|
@@ -30,9 +30,9 @@ classifiers = [
|
|
|
30
30
|
"Typing :: Typed",
|
|
31
31
|
]
|
|
32
32
|
dependencies = [
|
|
33
|
-
"json5>=0.
|
|
33
|
+
"json5>=0.15.0",
|
|
34
34
|
"pyyaml>=6.0.3",
|
|
35
|
-
"src-py-lib[otel]==0.3.
|
|
35
|
+
"src-py-lib[otel]==0.3.2",
|
|
36
36
|
]
|
|
37
37
|
keywords = [
|
|
38
38
|
"Sourcegraph"
|
|
@@ -63,9 +63,7 @@ line-length = 100
|
|
|
63
63
|
extend-exclude = ["src-auth-perms-sync-runs"]
|
|
64
64
|
|
|
65
65
|
[tool.ruff.lint]
|
|
66
|
-
#
|
|
67
|
-
# lookalike letters) in Python strings, comments, and docstrings;
|
|
68
|
-
# tests/confusables.py applies the same policy to non-Python files.
|
|
66
|
+
# tests/unicode_scan.py bans non-ASCII characters in tracked text files.
|
|
69
67
|
select = ["E", "F", "I", "B", "UP", "SIM", "RUF001", "RUF002", "RUF003"]
|
|
70
68
|
|
|
71
69
|
[tool.uv]
|