src-auth-perms-sync 0.7.0__tar.gz → 0.8.0__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.
Files changed (194) hide show
  1. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/.github/workflows/release.yml +2 -2
  2. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/.github/workflows/validate.yml +10 -7
  3. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/AGENTS.md +12 -13
  4. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/PKG-INFO +26 -26
  5. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/README.md +23 -23
  6. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/dev/TODO.md +5 -5
  7. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/dev/engineering-requests.md +10 -10
  8. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/dev/memory-analysis/memory-efficiency-analyze.py +1 -1
  9. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/examples/import.py +3 -3
  10. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/examples/maps.yaml +2 -2
  11. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/pyproject.toml +5 -7
  12. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/cli.py +104 -95
  13. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/orgs/sync.py +76 -13
  14. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/permissions/apply.py +8 -8
  15. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/permissions/command.py +41 -32
  16. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/permissions/full_set.py +11 -11
  17. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/permissions/mapping.py +16 -16
  18. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/permissions/maps.py +93 -74
  19. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/permissions/queries.py +3 -3
  20. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/permissions/restore.py +9 -9
  21. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/permissions/snapshot.py +9 -9
  22. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/permissions/sourcegraph.py +10 -6
  23. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/permissions/types.py +1 -1
  24. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/permissions/workflow.py +4 -4
  25. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/shared/backups.py +3 -3
  26. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/shared/run_context.py +3 -3
  27. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/shared/saml_groups.py +12 -11
  28. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/shared/site_config.py +11 -11
  29. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/shared/sourcegraph.py +1 -1
  30. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/shared/types.py +1 -0
  31. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/README.md +23 -23
  32. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/case_runner.py +17 -14
  33. src_auth_perms_sync-0.8.0/tests/e2e/fixtures/set-users-sync-saml-orgs-noop/after.json +114 -0
  34. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-sync-saml-orgs-scoped/after.json +1 -1
  35. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/sync-saml-orgs-full-cleanup/after.json +1 -1
  36. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/sync-saml-orgs-users-scoped/after.json +1 -1
  37. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/test_local_cases.py +4 -4
  38. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/integration/test_cli_entrypoint.py +8 -1
  39. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/run.py +285 -30
  40. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/setup.py +220 -7
  41. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/tests.yaml +50 -46
  42. src_auth_perms_sync-0.8.0/tests/unicode_scan.py +65 -0
  43. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/unit/test_backups.py +3 -3
  44. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/unit/test_cli_config.py +32 -30
  45. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/unit/test_command_additive.py +2 -2
  46. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/unit/test_command_files.py +16 -8
  47. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/unit/test_maps.py +3 -2
  48. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/unit/test_permissions_sourcegraph.py +2 -2
  49. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/unit/test_restore.py +4 -4
  50. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/unit/test_saml_groups.py +12 -6
  51. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/unit/test_snapshot.py +1 -1
  52. src_auth_perms_sync-0.8.0/tests/unit/test_unicode_scan.py +22 -0
  53. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/uv.lock +50 -50
  54. src_auth_perms_sync-0.7.0/tests/confusables.py +0 -215
  55. src_auth_perms_sync-0.7.0/tests/unit/test_confusables.py +0 -35
  56. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/.github/CODEOWNERS +0 -0
  57. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/.github/workflows/ci.yml +0 -0
  58. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/.gitignore +0 -0
  59. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/.markdownlint-cli2.yaml +0 -0
  60. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/.python-version +0 -0
  61. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/LICENSE +0 -0
  62. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/SECURITY.md +0 -0
  63. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/dev/audit-dead-code.md +0 -0
  64. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/dev/hooks/pre-commit +0 -0
  65. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/dev/memory-analysis/mapping-efficiency.md +0 -0
  66. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/dev/memory-analysis/memory-efficiency-generate.py +0 -0
  67. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/dev/memory-analysis/memory-efficiency-monitor-sourcegraph.sh +0 -0
  68. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/dev/memory-analysis/memory-efficiency.md +0 -0
  69. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/dev/update-python-versions.md +0 -0
  70. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/package-lock.json +0 -0
  71. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/package.json +0 -0
  72. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/renovate.json +0 -0
  73. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/__init__.py +0 -0
  74. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/__main__.py +0 -0
  75. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/orgs/__init__.py +0 -0
  76. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/orgs/command.py +0 -0
  77. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/orgs/queries.py +0 -0
  78. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/orgs/types.py +0 -0
  79. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/permissions/__init__.py +0 -0
  80. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/shared/__init__.py +0 -0
  81. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/src/src_auth_perms_sync/shared/queries.py +0 -0
  82. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/__init__.py +0 -0
  83. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/__init__.py +0 -0
  84. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/add-users-by-email-and-list/after.json +0 -0
  85. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/add-users-by-email-and-list/before.json +0 -0
  86. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/add-users-by-email-and-list/maps.yaml +0 -0
  87. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/add-users-preserves-existing/after.json +0 -0
  88. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/add-users-preserves-existing/before.json +0 -0
  89. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/add-users-preserves-existing/maps.yaml +0 -0
  90. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/and-filters-intersect/after.json +0 -0
  91. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/and-filters-intersect/before.json +0 -0
  92. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/and-filters-intersect/maps.yaml +0 -0
  93. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/empty-maps-noop/before.json +0 -0
  94. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/empty-maps-noop/maps.yaml +0 -0
  95. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/full-overwrite-dry-run/before.json +0 -0
  96. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/full-overwrite-dry-run/maps.yaml +0 -0
  97. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/full-overwrite-preserves-pending/after.json +0 -0
  98. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/full-overwrite-preserves-pending/before.json +0 -0
  99. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/full-overwrite-preserves-pending/maps.yaml +0 -0
  100. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/full-overwrite-removes-stale-grant/after.json +0 -0
  101. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/full-overwrite-removes-stale-grant/before.json +0 -0
  102. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/full-overwrite-removes-stale-grant/maps.yaml +0 -0
  103. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/full-overwrite-unions/after.json +0 -0
  104. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/full-overwrite-unions/before.json +0 -0
  105. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/full-overwrite-unions/maps.yaml +0 -0
  106. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/full-overwrite-with-backup/after.json +0 -0
  107. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/full-overwrite-with-backup/before.json +0 -0
  108. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/full-overwrite-with-backup/maps.yaml +0 -0
  109. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/get-full-snapshot/before.json +0 -0
  110. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/get-repos-without-explicit-perms/before.json +0 -0
  111. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/get-user-grants/before.json +0 -0
  112. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/invalid-bad-regex/before.json +0 -0
  113. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/invalid-bad-regex/maps.yaml +0 -0
  114. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/invalid-missing-repos-section/before.json +0 -0
  115. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/invalid-missing-repos-section/maps.yaml +0 -0
  116. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/invalid-restore-wrong-schema-version/before.json +0 -0
  117. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/invalid-restore-wrong-schema-version/snapshot.json +0 -0
  118. {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/invalid-set-created-after-date → src_auth_perms_sync-0.8.0/tests/e2e/fixtures/invalid-set-repos-created-after-date}/before.json +0 -0
  119. {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/invalid-set-created-after-date → src_auth_perms_sync-0.8.0/tests/e2e/fixtures/invalid-set-repos-created-after-date}/maps.yaml +0 -0
  120. {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/invalid-set-repos-created-after-date → src_auth_perms_sync-0.8.0/tests/e2e/fixtures/invalid-set-unknown-repo}/before.json +0 -0
  121. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/invalid-set-unknown-repo/maps.yaml +0 -0
  122. {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/invalid-set-unknown-repo → src_auth_perms_sync-0.8.0/tests/e2e/fixtures/invalid-set-unknown-user}/before.json +0 -0
  123. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/invalid-set-unknown-user/maps.yaml +0 -0
  124. {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/invalid-set-unknown-user → src_auth_perms_sync-0.8.0/tests/e2e/fixtures/invalid-set-users-created-after-date}/before.json +0 -0
  125. {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/invalid-set-repos-created-after-date → src_auth_perms_sync-0.8.0/tests/e2e/fixtures/invalid-set-users-created-after-date}/maps.yaml +0 -0
  126. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/invalid-unknown-selector-field/before.json +0 -0
  127. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/invalid-unknown-selector-field/maps.yaml +0 -0
  128. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/match-provider-and-host-fields/after.json +0 -0
  129. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/match-provider-and-host-fields/before.json +0 -0
  130. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/match-provider-and-host-fields/maps.yaml +0 -0
  131. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/no-match-noop/before.json +0 -0
  132. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/no-match-noop/maps.yaml +0 -0
  133. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/regex-filters-scope/after.json +0 -0
  134. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/regex-filters-scope/before.json +0 -0
  135. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/regex-filters-scope/maps.yaml +0 -0
  136. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/restore-applies-snapshot/after.json +0 -0
  137. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/restore-applies-snapshot/before.json +0 -0
  138. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/restore-applies-snapshot/snapshot.json +0 -0
  139. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/restore-dry-run-noop/before.json +0 -0
  140. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/restore-dry-run-noop/snapshot.json +0 -0
  141. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/restore-missing-file/before.json +0 -0
  142. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/restore-restores-pending/after.json +0 -0
  143. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/restore-restores-pending/before.json +0 -0
  144. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/restore-restores-pending/snapshot.json +0 -0
  145. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/saml-group-filter/after.json +0 -0
  146. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/saml-group-filter/before.json +0 -0
  147. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/saml-group-filter/maps.yaml +0 -0
  148. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/saml-group-live/after.json +0 -0
  149. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/saml-group-live/before.json +0 -0
  150. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/saml-group-live/maps.yaml +0 -0
  151. {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/set-created-after-sync-saml-orgs-dry-run → src_auth_perms_sync-0.8.0/tests/e2e/fixtures/set-full-sync-saml-orgs-dry-run}/maps.yaml +0 -0
  152. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-repos-created-after/after.json +0 -0
  153. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-repos-created-after/before.json +0 -0
  154. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-repos-created-after/maps.yaml +0 -0
  155. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-repos-created-after-noop/before.json +0 -0
  156. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-repos-created-after-noop/maps.yaml +0 -0
  157. {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/set-full-sync-saml-orgs-dry-run → src_auth_perms_sync-0.8.0/tests/e2e/fixtures/set-repos-created-after-sync-saml-orgs-dry-run}/maps.yaml +0 -0
  158. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-repos-filter/after.json +0 -0
  159. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-repos-filter/before.json +0 -0
  160. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-repos-filter/maps.yaml +0 -0
  161. {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.0/tests/e2e/fixtures/set-repos-sync-saml-orgs-dry-run}/maps.yaml +0 -0
  162. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-repos-without-explicit-perms/after.json +0 -0
  163. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-repos-without-explicit-perms/before.json +0 -0
  164. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-repos-without-explicit-perms/maps.yaml +0 -0
  165. {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/set-repos-sync-saml-orgs-dry-run → src_auth_perms_sync-0.8.0/tests/e2e/fixtures/set-repos-without-perms-sync-saml-orgs-dry-run}/maps.yaml +0 -0
  166. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-created-after/after.json +0 -0
  167. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-created-after/before.json +0 -0
  168. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-created-after/maps.yaml +0 -0
  169. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-created-after-noop/before.json +0 -0
  170. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-created-after-noop/maps.yaml +0 -0
  171. {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.0/tests/e2e/fixtures/set-users-created-after-sync-saml-orgs-dry-run}/maps.yaml +0 -0
  172. {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/set-created-after-temp-user → src_auth_perms_sync-0.8.0/tests/e2e/fixtures/set-users-created-after-temp-user}/after.json +0 -0
  173. {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/set-created-after-temp-user → src_auth_perms_sync-0.8.0/tests/e2e/fixtures/set-users-created-after-temp-user}/before.json +0 -0
  174. {src_auth_perms_sync-0.7.0/tests/e2e/fixtures/set-created-after-temp-user → src_auth_perms_sync-0.8.0/tests/e2e/fixtures/set-users-created-after-temp-user}/maps.yaml +0 -0
  175. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-sync-saml-orgs-dry-run/maps.yaml +0 -0
  176. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-sync-saml-orgs-noop/before.json +0 -0
  177. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-sync-saml-orgs-noop/maps.yaml +0 -0
  178. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-sync-saml-orgs-scoped/before.json +0 -0
  179. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-sync-saml-orgs-scoped/maps.yaml +0 -0
  180. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-without-explicit-perms/after.json +0 -0
  181. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-without-explicit-perms/before.json +0 -0
  182. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-without-explicit-perms/maps.yaml +0 -0
  183. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-without-explicit-perms-default-batch/after.json +0 -0
  184. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-without-explicit-perms-default-batch/before.json +0 -0
  185. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-without-explicit-perms-default-batch/maps.yaml +0 -0
  186. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/set-users-without-perms-sync-saml-orgs-dry-run/maps.yaml +0 -0
  187. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/sync-saml-orgs-full-cleanup/before.json +0 -0
  188. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/e2e/fixtures/sync-saml-orgs-users-scoped/before.json +0 -0
  189. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/integration/__init__.py +0 -0
  190. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/setup.yaml +0 -0
  191. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/unit/__init__.py +0 -0
  192. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/unit/test_apply.py +0 -0
  193. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/tests/unit/test_mapping_rules.py +0 -0
  194. {src_auth_perms_sync-0.7.0 → src_auth_perms_sync-0.8.0}/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@v6
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@v5
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@v6
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@v6
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@v5
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@v6
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@v5
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@v6
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@v5
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
- ### Confusable Unicode characters in non-Python files
18
- # (ruff RUF001-RUF003 covers Python strings/comments/docstrings)
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, confusable-character scan, unit + fixture
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>/` — see the README there
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 — do not break
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` — `main()`, arg parsing, owns the CLI description. Module
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/` — cross-workflow helpers: Sourcegraph auth-provider/user list
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 — never recompute paths
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/` — repo permission sync (`command.py`, `maps.py`,
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/` — SAML group → Sourcegraph organization sync (`command.py`,
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 — prefer `user`, `repo`,
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.7.0
3
+ Version: 0.8.0
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.14.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.0
21
+ Requires-Dist: src-py-lib[otel]==0.3.1
22
22
  Description-Content-Type: text/markdown
23
23
 
24
24
  # src-auth-perms-sync
25
- <!-- HUMAN-MAINTAINED SECTION START — DO NOT EDIT THIS SECTION -->
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 code_host in get_result.code_hosts:
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 — those apply to the CLI only. Pass every value explicitly to
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 — your
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-hosts.yaml` under
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 — there
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 — no surprises:
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
- ├── auth-providers.yaml
353
- ├── code-hosts.yaml
354
- ├── maps.yaml
355
- └── runs
356
- └── timestamp-command
357
- ├── before.json
358
- ├── after.json
359
- ├── diff.json
360
- ├── log.json
361
- └── maps.yaml
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-hosts.yaml` are created / replaced by the `get` command,
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 — DO NOT EDIT ABOVE -->
379
+ <!-- HUMAN-MAINTAINED SECTION END - DO NOT EDIT ABOVE -->
@@ -1,5 +1,5 @@
1
1
  # src-auth-perms-sync
2
- <!-- HUMAN-MAINTAINED SECTION START — DO NOT EDIT THIS SECTION -->
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 code_host in get_result.code_hosts:
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 — those apply to the CLI only. Pass every value explicitly to
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 — your
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-hosts.yaml` under
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 — there
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 — no surprises:
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
- ├── auth-providers.yaml
330
- ├── code-hosts.yaml
331
- ├── maps.yaml
332
- └── runs
333
- └── timestamp-command
334
- ├── before.json
335
- ├── after.json
336
- ├── diff.json
337
- ├── log.json
338
- └── maps.yaml
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-hosts.yaml` are created / replaced by the `get` command,
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 — DO NOT EDIT ABOVE -->
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 — see the repo-centric
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→users
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→users.** Once
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 — the previous code did neither.
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→teams), and
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** — pure CPU, no lock
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 → 2-4 users/sec at 4-way
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 — **below the 23 users/sec a
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 — the edge and frontend
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 ≈ 224.7ms/user). A
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** — a full `repo` ⋈
162
- `external_service_repos` ⋈ `external_services` join with the correlated
163
- authz `EXISTS` predicate and an `ORDER BY` — before the outer query applies
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 — ~225ms x probed user — is exactly what the
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-hosts.yaml` and `auth-providers.yaml`, then uses
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²: {r_squared}")
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 code_host in discovery.code_hosts:
32
- print("code host:", code_host.get("displayName"))
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 → Repo permission mapping rules
1
+ # User -> Repo permission mapping rules
2
2
 
3
- # Maintain your maps.yaml file, using the values from auth-providers.yaml and code-hosts.yaml,
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.410",
8
- "ruff>=0.15.17",
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.14.0",
33
+ "json5>=0.15.0",
34
34
  "pyyaml>=6.0.3",
35
- "src-py-lib[otel]==0.3.0",
35
+ "src-py-lib[otel]==0.3.1",
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
- # RUF001-RUF003 ban confusable Unicode (en dash, multiplication sign,
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]