aviato 0.3.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. aviato-0.3.0/LICENSE +21 -0
  2. aviato-0.3.0/PKG-INFO +21 -0
  3. aviato-0.3.0/README.md +331 -0
  4. aviato-0.3.0/aviato/__init__.py +33 -0
  5. aviato-0.3.0/aviato/audit.py +114 -0
  6. aviato-0.3.0/aviato/cli.py +2554 -0
  7. aviato-0.3.0/aviato/command.py +55 -0
  8. aviato-0.3.0/aviato/core/__init__.py +6 -0
  9. aviato-0.3.0/aviato/core/bootstrap.py +33 -0
  10. aviato-0.3.0/aviato/core/composition.py +489 -0
  11. aviato-0.3.0/aviato/core/consent.py +49 -0
  12. aviato-0.3.0/aviato/core/declaration.py +153 -0
  13. aviato-0.3.0/aviato/core/diagnosis.py +234 -0
  14. aviato-0.3.0/aviato/core/errors.py +33 -0
  15. aviato-0.3.0/aviato/core/file_drift_flow.py +65 -0
  16. aviato-0.3.0/aviato/core/filedrift.py +28 -0
  17. aviato-0.3.0/aviato/core/fleet.py +126 -0
  18. aviato-0.3.0/aviato/core/listmerge.py +67 -0
  19. aviato-0.3.0/aviato/core/mapmerge.py +21 -0
  20. aviato-0.3.0/aviato/core/marker.py +100 -0
  21. aviato-0.3.0/aviato/core/model.py +127 -0
  22. aviato-0.3.0/aviato/core/offboarding.py +138 -0
  23. aviato-0.3.0/aviato/core/onboarding.py +266 -0
  24. aviato-0.3.0/aviato/core/pathguard.py +45 -0
  25. aviato-0.3.0/aviato/core/ports.py +67 -0
  26. aviato-0.3.0/aviato/core/provision.py +94 -0
  27. aviato-0.3.0/aviato/core/reconcile.py +150 -0
  28. aviato-0.3.0/aviato/core/reconcile_flow.py +153 -0
  29. aviato-0.3.0/aviato/core/registry.py +212 -0
  30. aviato-0.3.0/aviato/core/render.py +29 -0
  31. aviato-0.3.0/aviato/core/repin.py +129 -0
  32. aviato-0.3.0/aviato/core/scaffold.py +405 -0
  33. aviato-0.3.0/aviato/core/selfcheck.py +156 -0
  34. aviato-0.3.0/aviato/core/settings_drift_flow.py +166 -0
  35. aviato-0.3.0/aviato/core/settingsdrift.py +142 -0
  36. aviato-0.3.0/aviato/core/variables.py +140 -0
  37. aviato-0.3.0/aviato/core/version.py +103 -0
  38. aviato-0.3.0/aviato/core/versioning.py +117 -0
  39. aviato-0.3.0/aviato/github.py +511 -0
  40. aviato-0.3.0/aviato/github_platform.py +1086 -0
  41. aviato-0.3.0/aviato/library/aviato-library.yaml +27 -0
  42. aviato-0.3.0/aviato/library/bundles/scaffold/aviato-library-sc.yaml +12 -0
  43. aviato-0.3.0/aviato/library/bundles/scaffold/common.yaml +14 -0
  44. aviato-0.3.0/aviato/library/bundles/scaffold/node-sc.yaml +10 -0
  45. aviato-0.3.0/aviato/library/bundles/scaffold/node-service-sc.yaml +12 -0
  46. aviato-0.3.0/aviato/library/bundles/scaffold/python-component-sc.yaml +12 -0
  47. aviato-0.3.0/aviato/library/bundles/scaffold/python-library-sc.yaml +12 -0
  48. aviato-0.3.0/aviato/library/bundles/scaffold/python-sc.yaml +7 -0
  49. aviato-0.3.0/aviato/library/bundles/scaffold/python-service-sc.yaml +24 -0
  50. aviato-0.3.0/aviato/library/bundles/scaffold/swift-app-sc.yaml +12 -0
  51. aviato-0.3.0/aviato/library/bundles/scaffold/swift-sc.yaml +6 -0
  52. aviato-0.3.0/aviato/library/bundles/settings/baseline.yaml +43 -0
  53. aviato-0.3.0/aviato/library/bundles/workflows/base.yaml +9 -0
  54. aviato-0.3.0/aviato/library/bundles/workflows/node-service-wf.yaml +7 -0
  55. aviato-0.3.0/aviato/library/bundles/workflows/python-component-wf.yaml +8 -0
  56. aviato-0.3.0/aviato/library/bundles/workflows/python-library-wf.yaml +7 -0
  57. aviato-0.3.0/aviato/library/bundles/workflows/python-service-wf.yaml +7 -0
  58. aviato-0.3.0/aviato/library/bundles/workflows/swift-app-wf.yaml +7 -0
  59. aviato-0.3.0/aviato/library/docs-toolchain.yaml +3 -0
  60. aviato-0.3.0/aviato/library/node-service.yaml +38 -0
  61. aviato-0.3.0/aviato/library/pipelines.yaml +85 -0
  62. aviato-0.3.0/aviato/library/policy.yml +25 -0
  63. aviato-0.3.0/aviato/library/python-component.yaml +36 -0
  64. aviato-0.3.0/aviato/library/python-library.yaml +35 -0
  65. aviato-0.3.0/aviato/library/python-service.yaml +44 -0
  66. aviato-0.3.0/aviato/library/rulesets/protect-default-branch.json +60 -0
  67. aviato-0.3.0/aviato/library/rulesets/release-tag-format.json +41 -0
  68. aviato-0.3.0/aviato/library/rulesets.yml +13 -0
  69. aviato-0.3.0/aviato/library/scaffold/codeowners.yaml +4 -0
  70. aviato-0.3.0/aviato/library/scaffold/contributing.yaml +4 -0
  71. aviato-0.3.0/aviato/library/scaffold/docs-intro.yaml +6 -0
  72. aviato-0.3.0/aviato/library/scaffold/docs-requirements.yaml +7 -0
  73. aviato-0.3.0/aviato/library/scaffold/editorconfig.yaml +5 -0
  74. aviato-0.3.0/aviato/library/scaffold/files/VERSION.txt +1 -0
  75. aviato-0.3.0/aviato/library/scaffold/files/codeowners.txt +3 -0
  76. aviato-0.3.0/aviato/library/scaffold/files/contributing.md.txt +16 -0
  77. aviato-0.3.0/aviato/library/scaffold/files/docs-intro.md.txt +7 -0
  78. aviato-0.3.0/aviato/library/scaffold/files/docs-requirements.txt.txt +3 -0
  79. aviato-0.3.0/aviato/library/scaffold/files/editorconfig.txt +12 -0
  80. aviato-0.3.0/aviato/library/scaffold/files/eslint.config.mjs.txt +10 -0
  81. aviato-0.3.0/aviato/library/scaffold/files/gitignore-common.txt +24 -0
  82. aviato-0.3.0/aviato/library/scaffold/files/issue-template-bug.md.txt +17 -0
  83. aviato-0.3.0/aviato/library/scaffold/files/issue-template-feature.md.txt +17 -0
  84. aviato-0.3.0/aviato/library/scaffold/files/license.txt +21 -0
  85. aviato-0.3.0/aviato/library/scaffold/files/mypy-service.ini.txt +7 -0
  86. aviato-0.3.0/aviato/library/scaffold/files/mypy.ini.txt +5 -0
  87. aviato-0.3.0/aviato/library/scaffold/files/npmrc.txt +3 -0
  88. aviato-0.3.0/aviato/library/scaffold/files/package.json.js.txt +23 -0
  89. aviato-0.3.0/aviato/library/scaffold/files/package.json.ts.txt +25 -0
  90. aviato-0.3.0/aviato/library/scaffold/files/pr-template.md.txt +12 -0
  91. aviato-0.3.0/aviato/library/scaffold/files/prettierrc.json.txt +5 -0
  92. aviato-0.3.0/aviato/library/scaffold/files/pyproject.toml.txt +37 -0
  93. aviato-0.3.0/aviato/library/scaffold/files/requirements-dev.txt.txt +9 -0
  94. aviato-0.3.0/aviato/library/scaffold/files/ruff.toml.txt +5 -0
  95. aviato-0.3.0/aviato/library/scaffold/files/swift-format.txt +6 -0
  96. aviato-0.3.0/aviato/library/scaffold/files/swiftlint.yml.txt +7 -0
  97. aviato-0.3.0/aviato/library/scaffold/files/tsconfig.json.txt +11 -0
  98. aviato-0.3.0/aviato/library/scaffold/files/wf-docs-node-service.yml +118 -0
  99. aviato-0.3.0/aviato/library/scaffold/files/wf-docs-python-component.yml +118 -0
  100. aviato-0.3.0/aviato/library/scaffold/files/wf-docs-python-library.yml +118 -0
  101. aviato-0.3.0/aviato/library/scaffold/files/wf-docs-python-service.yml +114 -0
  102. aviato-0.3.0/aviato/library/scaffold/files/wf-docs-swift-app.yml +112 -0
  103. aviato-0.3.0/aviato/library/scaffold/files/wf-drift.yml +28 -0
  104. aviato-0.3.0/aviato/library/scaffold/files/wf-node-service.yml +120 -0
  105. aviato-0.3.0/aviato/library/scaffold/files/wf-python-component.yml +107 -0
  106. aviato-0.3.0/aviato/library/scaffold/files/wf-python-library.yml +313 -0
  107. aviato-0.3.0/aviato/library/scaffold/files/wf-python-service.yml +129 -0
  108. aviato-0.3.0/aviato/library/scaffold/files/wf-swift-app.yml +134 -0
  109. aviato-0.3.0/aviato/library/scaffold/files/zensical.toml.txt +10 -0
  110. aviato-0.3.0/aviato/library/scaffold/gitignore-common.yaml +5 -0
  111. aviato-0.3.0/aviato/library/scaffold/issue-template-bug.yaml +4 -0
  112. aviato-0.3.0/aviato/library/scaffold/issue-template-feature.yaml +4 -0
  113. aviato-0.3.0/aviato/library/scaffold/license.yaml +4 -0
  114. aviato-0.3.0/aviato/library/scaffold/node-format-config.yaml +4 -0
  115. aviato-0.3.0/aviato/library/scaffold/node-lint-config.yaml +5 -0
  116. aviato-0.3.0/aviato/library/scaffold/node-manifest-js.yaml +8 -0
  117. aviato-0.3.0/aviato/library/scaffold/node-manifest.yaml +7 -0
  118. aviato-0.3.0/aviato/library/scaffold/node-tsconfig.yaml +7 -0
  119. aviato-0.3.0/aviato/library/scaffold/npmrc.yaml +5 -0
  120. aviato-0.3.0/aviato/library/scaffold/pr-template.yaml +4 -0
  121. aviato-0.3.0/aviato/library/scaffold/python-dev-deps.yaml +6 -0
  122. aviato-0.3.0/aviato/library/scaffold/python-lint-config.yaml +5 -0
  123. aviato-0.3.0/aviato/library/scaffold/python-manifest.yaml +6 -0
  124. aviato-0.3.0/aviato/library/scaffold/python-typecheck-config-service.yaml +8 -0
  125. aviato-0.3.0/aviato/library/scaffold/python-typecheck-config.yaml +5 -0
  126. aviato-0.3.0/aviato/library/scaffold/python-version-file.yaml +6 -0
  127. aviato-0.3.0/aviato/library/scaffold/swift-format-config.yaml +4 -0
  128. aviato-0.3.0/aviato/library/scaffold/swift-lint-config.yaml +5 -0
  129. aviato-0.3.0/aviato/library/scaffold/wf-ci-node-service.yaml +5 -0
  130. aviato-0.3.0/aviato/library/scaffold/wf-ci-python-component.yaml +5 -0
  131. aviato-0.3.0/aviato/library/scaffold/wf-ci-python-library.yaml +5 -0
  132. aviato-0.3.0/aviato/library/scaffold/wf-ci-python-service.yaml +5 -0
  133. aviato-0.3.0/aviato/library/scaffold/wf-ci-swift-app.yaml +5 -0
  134. aviato-0.3.0/aviato/library/scaffold/wf-docs-node-service.yaml +7 -0
  135. aviato-0.3.0/aviato/library/scaffold/wf-docs-python-component.yaml +7 -0
  136. aviato-0.3.0/aviato/library/scaffold/wf-docs-python-library.yaml +7 -0
  137. aviato-0.3.0/aviato/library/scaffold/wf-docs-python-service.yaml +7 -0
  138. aviato-0.3.0/aviato/library/scaffold/wf-docs-swift-app.yaml +7 -0
  139. aviato-0.3.0/aviato/library/scaffold/wf-drift.yaml +5 -0
  140. aviato-0.3.0/aviato/library/scaffold/zensical-config.yaml +7 -0
  141. aviato-0.3.0/aviato/library/swift-app.yaml +49 -0
  142. aviato-0.3.0/aviato/library/zizmor.yml +25 -0
  143. aviato-0.3.0/aviato/library_source.py +119 -0
  144. aviato-0.3.0/aviato/paths.py +26 -0
  145. aviato-0.3.0/aviato/plugins/__init__.py +6 -0
  146. aviato-0.3.0/aviato/plugins/actionpins.py +979 -0
  147. aviato-0.3.0/aviato/plugins/comment_syntax.py +36 -0
  148. aviato-0.3.0/aviato/plugins/denylist.txt +41 -0
  149. aviato-0.3.0/aviato/plugins/version_formats.py +223 -0
  150. aviato-0.3.0/aviato/plugins/zizmor_scan.py +116 -0
  151. aviato-0.3.0/aviato/policy.py +64 -0
  152. aviato-0.3.0/aviato/repos.py +120 -0
  153. aviato-0.3.0/aviato/rulesets.py +229 -0
  154. aviato-0.3.0/aviato/validation.py +1026 -0
  155. aviato-0.3.0/aviato.egg-info/PKG-INFO +21 -0
  156. aviato-0.3.0/aviato.egg-info/SOURCES.txt +192 -0
  157. aviato-0.3.0/aviato.egg-info/dependency_links.txt +1 -0
  158. aviato-0.3.0/aviato.egg-info/entry_points.txt +2 -0
  159. aviato-0.3.0/aviato.egg-info/requires.txt +14 -0
  160. aviato-0.3.0/aviato.egg-info/top_level.txt +1 -0
  161. aviato-0.3.0/pyproject.toml +70 -0
  162. aviato-0.3.0/setup.cfg +4 -0
  163. aviato-0.3.0/tests/test_audit.py +104 -0
  164. aviato-0.3.0/tests/test_cli_apply_rulesets.py +271 -0
  165. aviato-0.3.0/tests/test_cli_doctor.py +232 -0
  166. aviato-0.3.0/tests/test_cli_drift_report.py +318 -0
  167. aviato-0.3.0/tests/test_cli_is_highest.py +31 -0
  168. aviato-0.3.0/tests/test_cli_lint_actions.py +33 -0
  169. aviato-0.3.0/tests/test_cli_onboard.py +294 -0
  170. aviato-0.3.0/tests/test_cli_onboard_proposal.py +313 -0
  171. aviato-0.3.0/tests/test_cli_onboard_write.py +498 -0
  172. aviato-0.3.0/tests/test_cli_provision.py +291 -0
  173. aviato-0.3.0/tests/test_cli_reconcile.py +181 -0
  174. aviato-0.3.0/tests/test_cli_release.py +256 -0
  175. aviato-0.3.0/tests/test_cli_repin_offboard.py +426 -0
  176. aviato-0.3.0/tests/test_cli_scan.py +234 -0
  177. aviato-0.3.0/tests/test_cli_sync.py +198 -0
  178. aviato-0.3.0/tests/test_cli_version_pin.py +64 -0
  179. aviato-0.3.0/tests/test_command_hardening.py +98 -0
  180. aviato-0.3.0/tests/test_docs_index.py +490 -0
  181. aviato-0.3.0/tests/test_docs_toolchain_parity.py +210 -0
  182. aviato-0.3.0/tests/test_github.py +497 -0
  183. aviato-0.3.0/tests/test_github_failclosed.py +38 -0
  184. aviato-0.3.0/tests/test_github_platform.py +1511 -0
  185. aviato-0.3.0/tests/test_library_source.py +110 -0
  186. aviato-0.3.0/tests/test_local_gate.py +134 -0
  187. aviato-0.3.0/tests/test_pipeline_privileges.py +160 -0
  188. aviato-0.3.0/tests/test_policy.py +51 -0
  189. aviato-0.3.0/tests/test_repos.py +27 -0
  190. aviato-0.3.0/tests/test_rulesets.py +307 -0
  191. aviato-0.3.0/tests/test_starter_governance.py +69 -0
  192. aviato-0.3.0/tests/test_validation.py +28 -0
  193. aviato-0.3.0/tests/test_validation_negative.py +612 -0
  194. aviato-0.3.0/tests/test_workflow_guards.py +1559 -0
aviato-0.3.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anthony Mattas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
aviato-0.3.0/PKG-INFO ADDED
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: aviato
3
+ Version: 0.3.0
4
+ Summary: Reusable GitHub policy, CI, release, and onboarding conventions.
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.12
7
+ License-File: LICENSE
8
+ Requires-Dist: PyYAML>=6.0
9
+ Requires-Dist: zizmor==1.25.2
10
+ Requires-Dist: bashlex==0.18
11
+ Provides-Extra: dev
12
+ Requires-Dist: black==26.5.1; extra == "dev"
13
+ Requires-Dist: build==1.5.0; extra == "dev"
14
+ Requires-Dist: mypy==2.1.0; extra == "dev"
15
+ Requires-Dist: pytest==9.0.3; extra == "dev"
16
+ Requires-Dist: pytest-cov==7.1.0; extra == "dev"
17
+ Requires-Dist: ruff==0.15.16; extra == "dev"
18
+ Requires-Dist: types-PyYAML==6.0.12.20260518; extra == "dev"
19
+ Requires-Dist: setuptools>=69; extra == "dev"
20
+ Requires-Dist: yamllint==1.35.1; extra == "dev"
21
+ Dynamic: license-file
aviato-0.3.0/README.md ADDED
@@ -0,0 +1,331 @@
1
+ <p align="center">
2
+ <img src="docs/assets/aviato.jpg" alt="Aviato — Where code takes flight" width="520">
3
+ </p>
4
+
5
+ # Aviato
6
+
7
+ Aviato is a reusable GitHub policy, CI, release, and onboarding conventions
8
+ library. It centralizes shared workflows, rulesets, and operator tooling without
9
+ keeping a committed inventory of consumer repositories.
10
+
11
+ ## Policy
12
+
13
+ `aviato/library/policy.yml` is the canonical source for policy constants (it lives
14
+ inside the package so it ships in the wheel for installed ruleset rendering).
15
+
16
+ Release tags must match:
17
+
18
+ ```text
19
+ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-(alpha|beta)[0-9]+)?$
20
+ ```
21
+
22
+ Accepted examples: `1.2.3`, `1.2.3-alpha1`, `1.2.3-beta2`.
23
+
24
+ Rejected examples: `v1.2.3` (no `v` prefix allowed), `1.2.3-beta.1`,
25
+ `build-20260519.0215`.
26
+
27
+ Release publishing is tag-only. Legacy `release/*` branches should be cleaned up
28
+ in consumer repositories rather than supported by release publish workflows.
29
+
30
+ ## What Is Here
31
+
32
+ - `aviato/library/policy.yml` - canonical policy constants (packaged; ships in the wheel).
33
+ - `aviato/library/rulesets.yml` - ruleset manifest.
34
+ - `aviato/library/rulesets/*.json` - GitHub ruleset templates.
35
+ - `.github/workflows/reusable-*.yml` - reusable CI, release, deploy, and security workflows.
36
+ - `templates/profile-*.yml`, `templates/consumer-automation.yml` - composed, copyable
37
+ caller-workflow examples for consumer repos (rendered from the scaffold bundles; they
38
+ include the always-on security baseline, §2.13). Use these composed callers rather than
39
+ hand-wiring a single reusable workflow, which can omit the required baseline.
40
+ - `aviato/` - Python CLI implementation.
41
+ - `scripts/*.sh` - compatibility wrappers and validation entrypoints.
42
+
43
+ ## Commands
44
+
45
+ Install locally:
46
+
47
+ ```bash
48
+ python3 -m pip install -e .[dev]
49
+ ```
50
+
51
+ Audit repositories under a local root:
52
+
53
+ ```bash
54
+ aviato audit .
55
+ ```
56
+
57
+ Audit one repository:
58
+
59
+ ```bash
60
+ aviato audit --repo /Users/amattas/GitHub/example
61
+ ```
62
+
63
+ Dry-run the rulesets resolved from an adopted repository's declaration:
64
+
65
+ ```bash
66
+ aviato apply-rulesets amattas/example --declaration /path/to/example/.github/aviato.yaml
67
+ ```
68
+
69
+ Apply the reviewed declaration-resolved rulesets:
70
+
71
+ ```bash
72
+ aviato apply-rulesets amattas/example --declaration /path/to/example/.github/aviato.yaml --apply
73
+ ```
74
+
75
+ For a solo-maintainer repository, persist the liveness exception in its
76
+ declaration rather than relying on an ephemeral CLI flag:
77
+
78
+ ```yaml
79
+ overrides:
80
+ settings:
81
+ default_branch:
82
+ required_reviews: 0
83
+ ```
84
+
85
+ Then dry-run and apply using `--declaration` as above. Remove that override
86
+ before or in the same settings change that makes another reviewer eligible.
87
+
88
+ Validate this repository:
89
+
90
+ ```bash
91
+ ./scripts/validate.sh
92
+ ```
93
+
94
+ Onboard or provision consumers with an explicit published Library pin:
95
+
96
+ ```bash
97
+ aviato onboard /path/to/repo --profile python-library --pin 1.2.3 --write
98
+ aviato onboard amattas/example --profile python-library --pin 1.2.3 --open-pr # adopt an existing repo via a reviewable scaffold PR
99
+ aviato provision amattas/example --profile node-service --pin 1.2.3
100
+ ```
101
+
102
+ Local mutation is always explicit. `onboard` plans by default; `--write` applies
103
+ the plan, `--allow-dirty` acknowledges a non-clean worktree, and
104
+ `--migrate-profile` authorizes changing an existing declaration's stable profile
105
+ identity. Repeat `--var KEY=VALUE` for non-secret profile variables. Provisioning
106
+ is private by default; add `--public` only when the new repository is intended to
107
+ be public. `--override-version-pin` is the exceptional recovery switch for a
108
+ recorded-pin mismatch; ordinary pin movement uses `aviato repin`.
109
+
110
+ ```bash
111
+ aviato onboard /path/to/repo --profile python-service --pin 1.2.3 --docs --var serve-pages=true --write
112
+ aviato onboard /path/to/repo --profile python-service --pin 1.2.3 --migrate-profile --allow-dirty --write
113
+ aviato provision OWNER/REPO --profile node-service --pin 1.2.3 --var project-name=app --var language-variant=typescript --public
114
+ aviato sync /path/to/repo --override-version-pin
115
+ ```
116
+
117
+ `--docs` on `onboard`/`provision` composes the opt-in docs deploy.
118
+
119
+ Fresh writes and provisioning refuse to invent a default pin. The requested pin
120
+ must already resolve to a published Aviato tag or branch; use
121
+ `--allow-unresolved-pin` only for intentional offline or test scaffolds. Already
122
+ adopted repositories keep their recorded pin during onboarding; use
123
+ `aviato repin` to move it.
124
+
125
+ Consumer lifecycle commands (see `aviato <command> --help` for the full flags):
126
+
127
+ ```bash
128
+ aviato render-rulesets # print rendered ruleset JSON
129
+ aviato apply-rulesets OWNER/REPO --declaration /path/.github/aviato.yaml --apply # override-aware apply: resolves checks/approvals through the consumer's declared overrides (what settings-drift remediation recommends)
130
+ aviato doctor /path/to/consumer # classify managed artifacts + probe health
131
+ aviato sync /path/to/consumer # materialize managed artifacts incl. caller workflows
132
+ aviato scan /path/a /path/b [--fix --audit] # fleet diagnosis; --fix opens managed-file proposals, --audit surfaces open settings-drift tracking issues
133
+ aviato drift-report /path/to/consumer [--file-only|--settings-only] [--require-settings] # file + settings drift report
134
+ aviato reconcile /path/to/consumer ISSUE --confirm DIFF_ID # operator-gated settings apply, diff-bound
135
+ aviato complete-protection /path/to/consumer # idempotently (re-)apply full branch protection
136
+ aviato repin /path/to/consumer 1.3.0 [--write | --open-pr] # move the Library version pin; --open-pr opens a reviewable re-pin proposal
137
+ aviato offboard /path/to/consumer [--write --delete-files | --open-pr] # remove from Aviato management; --open-pr opens a reviewable removal proposal
138
+ aviato next-version --current 1.2.3 --commit "feat: x" # derive the next SemVer from Conventional Commits
139
+ aviato bump-version 1.3.0 /path/to/consumer # write the version into version-source locations
140
+ aviato is-highest 1.2.3 1.0.0 1.2.3 # exit 0 iff arg1 is the highest release among the rest
141
+ aviato lint-actions PATH # supply-chain pinning gate (zizmor + fail-closed curl|bash)
142
+ aviato validate # validate this repository's policy infrastructure (source checkout only)
143
+ ```
144
+
145
+ `scan` is read-only unless `--fix` is supplied; `--fix` opens managed-file
146
+ proposals and `--audit` also reports the open settings-drift issue. `offboard
147
+ --write` removes Aviato's declaration/management state but preserves managed
148
+ files unless `--delete-files` is also supplied. If `doctor` reports missing or
149
+ corrupt seed integrity state, inspect the files first, then explicitly accept the
150
+ current seed-once contents as the new baseline:
151
+
152
+ ```bash
153
+ aviato scan /path/to/fleet --fix --audit
154
+ aviato offboard /path/to/consumer --write --delete-files
155
+ aviato sync /path/to/consumer --rebaseline-seeds
156
+ ```
157
+
158
+ ### Operator setup and live verification
159
+
160
+ Repository and service controls are deliberately operator-run. Apply the full
161
+ rulesets first; on GitHub plans that do not support tag metadata restrictions,
162
+ the command reports a loud degraded posture while retaining tag deletion and
163
+ non-fast-forward protection. Any unrelated API failure remains fatal.
164
+
165
+ ```bash
166
+ aviato apply-rulesets OWNER/REPO --apply --declaration /path/to/checkout/.github/aviato.yaml
167
+ gh api --paginate repos/OWNER/REPO/rulesets
168
+ # The list endpoint is only a summary. Fetch every full live payload for amattas/aviato:
169
+ for id in $(gh api --paginate repos/amattas/aviato/rulesets --jq '.[].id'); do
170
+ gh api "repos/amattas/aviato/rulesets/${id}"
171
+ done
172
+ gh api --method PUT repos/OWNER/REPO/automated-security-fixes
173
+ ```
174
+
175
+ For PyPI or TestPyPI Trusted Publishing, register the consumer repository's
176
+ `.github/workflows/aviato-ci.yml` and protected `pypi` environment with the
177
+ project. The publishing job must remain in that consumer workflow so its OIDC
178
+ identity matches the registration; do not fall back to an API token.
179
+
180
+ ```bash
181
+ # Required reviewers are an operator prerequisite; configure at least one in protection.json.
182
+ gh api --method PUT repos/OWNER/REPO/environments/pypi --input protection.json
183
+ gh api repos/OWNER/REPO/environments/pypi
184
+ ```
185
+
186
+ In the PyPI/TestPyPI project UI, enter exactly: owner `OWNER`, repository
187
+ `REPO`, workflow `aviato-ci.yml`, environment `pypi`. Registration is an
188
+ out-of-band service operation; Aviato never stores a publishing credential.
189
+ GitHub enforces the configured environment gate, and `aviato doctor` plus
190
+ operator verification checks the required-reviewer posture when applicable.
191
+ Only the App Store workflow has an additional explicit fail-closed runtime
192
+ preflight of the environment's reviewer list; the PyPI publisher does not.
193
+
194
+ Docs are always versioned onto `gh-pages` when `docs: true`. To serve them, set
195
+ the non-secret profile variable `serve-pages: true`, configure Pages for the
196
+ custom workflow build type, and verify the same release run contains a successful
197
+ job ID `deploy`, with display name `Deploy GitHub Pages`. That job invokes the
198
+ `actions/deploy-pages` action; `deploy-pages` is the action name, not Aviato's
199
+ job/check name:
200
+
201
+ ```bash
202
+ gh api --method PUT repos/OWNER/REPO/pages -f build_type=workflow
203
+ gh api repos/OWNER/REPO/pages
204
+ gh run list --repo OWNER/REPO --limit 20
205
+ ```
206
+
207
+ Before treating a rollout as live-verified, run the local gate and inspect the
208
+ exact external evidence (PR check/status SHA, full ruleset payloads, open CodeQL
209
+ alerts, package index entry, Pages URL, and App Store receipt release asset):
210
+
211
+ ```bash
212
+ AVIATO_STRICT_TOOLS=1 ./scripts/validate.sh
213
+ aviato doctor .
214
+ gh api --paginate repos/OWNER/REPO/code-scanning/alerts -f state=open -f tool_name=CodeQL --method GET
215
+ gh pr view PR_NUMBER --repo OWNER/REPO --json mergeable,mergeStateStatus,statusCheckRollup
216
+ gh release view RELEASE_TAG --repo OWNER/REPO --json url,assets
217
+ ```
218
+
219
+ The legacy script names still work:
220
+
221
+ ```bash
222
+ ./scripts/audit-repos.sh .
223
+ ./scripts/apply-rulesets.sh --repo amattas/example --declaration /path/to/example/.github/aviato.yaml --apply
224
+ ```
225
+
226
+ ## Reusable Workflows
227
+
228
+ - `reusable-python-ci.yml`
229
+ - `reusable-node-ci.yml`
230
+ - `reusable-swift-ci.yml`
231
+ - `reusable-release.yml`
232
+ - `reusable-release-gate.yml`
233
+ - `reusable-docker-ghcr.yml`
234
+ - `reusable-pypi-publish.yml`
235
+ - `reusable-docs-pages.yml`
236
+ - `reusable-app-store-connect.yml`
237
+ - `reusable-security-baseline.yml`
238
+ - `reusable-common-lint.yml`
239
+ - `reusable-consumer-automation.yml`
240
+
241
+ `reusable-release.yml` is split into a read-only derive job and a write release
242
+ job. `reusable-release-gate.yml` exports the validated commit as a `gated-sha`
243
+ output; the deploy workflows check out that exact commit — never the mutable
244
+ tag — and re-verify the tag still points at it before publishing. The GHCR
245
+ publish promotes the exact Trivy-scanned OCI archives by digest (no rebuild
246
+ between scan and push), and the PyPI/GHCR publish jobs run in GitHub deployment
247
+ environments (defaults `pypi`/`ghcr`).
248
+
249
+ Language CI workflows share the same command contract:
250
+
251
+ - `working-directory`
252
+ - `install-command`
253
+ - `lint-command`
254
+ - `test-command`
255
+ - `build-command`
256
+ - `run-install`
257
+ - `run-lint`
258
+ - `run-tests`
259
+ - `run-build`
260
+
261
+ `reusable-node-ci.yml` defaults to Node 24 and blocks npm versions below 11.10
262
+ (the floor for `min-release-age` support) before any install command. It sets
263
+ `ignore-scripts=true`, `engine-strict=true`, and `min-release-age=7`; Node
264
+ scaffolds also write those values into managed `.npmrc` files and declare
265
+ `node >=24` / `npm >=11.10` in package manifests so local and CI installs share
266
+ the same supply-chain posture. Node CI uses `npx --no-install` for local tool
267
+ bins, and the common lint gate rejects unsafe plain `npx` registry fetches.
268
+
269
+ ## Profile Templates
270
+
271
+ The `templates/profile-*.yml` files compose CI, security, release validation,
272
+ and deployment jobs for common repo shapes:
273
+
274
+ - `profile-python-service.yml`
275
+ - `profile-python-library.yml`
276
+ - `profile-python-component.yml`
277
+ - `profile-node-service.yml`
278
+ - `profile-swift-app.yml`
279
+
280
+ These are **examples rendered from** the authoritative scaffold bundles
281
+ (`aviato/library/scaffold/files/wf-*.yml`); `aviato validate` fails if they drift,
282
+ and `python3 scripts/regen-templates.py` regenerates them. Prefer materializing the
283
+ real workflows with `aviato sync` / `aviato onboard --write`; committed examples
284
+ use the literal `EXAMPLE_PIN` placeholder instead of a production ref. Use
285
+ `aviato onboard TARGET --profile PROFILE` to list the exact artifacts, secrets,
286
+ rulesets, and protected deployment environments for a repository. The Python
287
+ library plan requires `pypi`, container profiles require `ghcr`, and the Swift
288
+ app plan requires the configured `environment-name` (`app-store-connect` by
289
+ default); each named environment must exist with at
290
+ least one required reviewer before deployment. Zero-deploy profiles explicitly
291
+ report that none are required. The common scaffold also seeds `CONTRIBUTING.md`,
292
+ `.github/CODEOWNERS`, and issue/PR templates (seed-once; the consumer owns them
293
+ after seeding).
294
+
295
+ When `docs: true`, Aviato scaffolds a **Zensical** docs site under `website/`,
296
+ versioned onto a docs branch by a mike fork (Mermaid rendering and sitemap
297
+ generation included; search is Zensical's built-in search, no external service).
298
+ The docs publish workflow installs, versions, builds, and publishes the site
299
+ on release refs;
300
+ `docs-retention` defaults to 0, which keeps every released version's docs.
301
+
302
+ The Library's own `.github/aviato.yaml` uses the internal `aviato-library`
303
+ profile and `bootstrap: true`. `local-install: true` is valid only for this
304
+ structural Library bootstrap path; reusable workflows fail before
305
+ `pip install -e .` if a consumer tries to enable it.
306
+
307
+ ## App Store Connect
308
+
309
+ The App Store Connect workflow runs on release tags, uses macOS, and must be
310
+ called behind a protected deployment environment. Required secrets are:
311
+
312
+ - `APP_STORE_CONNECT_ISSUER_ID`
313
+ - `APP_STORE_CONNECT_KEY_ID`
314
+ - `APP_STORE_CONNECT_API_PRIVATE_KEY`
315
+ - `APPLE_CERTIFICATE_P12_BASE64`
316
+ - `APPLE_CERTIFICATE_PASSWORD`
317
+ - `APPLE_PROVISIONING_PROFILE_BASE64`
318
+
319
+ The caller must provide project-specific Xcode inputs such as scheme, workspace
320
+ or project, export options plist, and version/build-number command.
321
+
322
+ Apple/App Store Connect credentials are scoped to the specific workflow steps
323
+ that need them. The caller-controlled version command runs before signing assets
324
+ are installed, so Apple secrets are not exposed to arbitrary versioning logic.
325
+
326
+ ## Architecture
327
+
328
+ See `docs/requirements/` for outcomes and constraints,
329
+ `docs/specifications/` for precise testable behavior, `docs/architecture/` for
330
+ the current implementation map, and `docs/security/` for threats and controls.
331
+ The § citation index remains `docs/requirements/README.md`.
@@ -0,0 +1,33 @@
1
+ """Aviato policy and repository tooling."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ import tomllib
7
+ from importlib import metadata
8
+ from pathlib import Path
9
+
10
+ __all__ = ["__version__"]
11
+
12
+ _SEMVER_RE = re.compile(r"^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-(?:alpha|beta)[0-9]+)?$")
13
+
14
+
15
+ def _source_version() -> str:
16
+ pyproject = Path(__file__).resolve().parent.parent / "pyproject.toml"
17
+ project = tomllib.loads(pyproject.read_text(encoding="utf-8")).get("project")
18
+ version = project.get("version") if isinstance(project, dict) else None
19
+ if not isinstance(version, str):
20
+ raise RuntimeError(f"{pyproject} does not define project.version")
21
+ if _SEMVER_RE.fullmatch(version) is None:
22
+ raise RuntimeError(f"{pyproject} project.version is not valid SemVer: {version!r}")
23
+ return version
24
+
25
+
26
+ def _runtime_version() -> str:
27
+ try:
28
+ return metadata.version("aviato")
29
+ except metadata.PackageNotFoundError:
30
+ return _source_version()
31
+
32
+
33
+ __version__ = _runtime_version()
@@ -0,0 +1,114 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import re
5
+ from collections.abc import Iterable
6
+ from dataclasses import asdict, dataclass
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from . import github
11
+ from .github import GitHubAPIError
12
+ from .policy import release_tag_pattern
13
+ from .repos import current_branch, discover_repos, normalize_slug, remote_url, tags, workflow_files
14
+
15
+ # R3-14/§5.9/§6.1: a bare floating-major tag (`1`, `2`) is a SANCTIONED release alias (the tag
16
+ # ruleset explicitly excludes it from the exact-SemVer pattern), so it is not an "invalid" tag.
17
+ _FLOATING_MAJOR_RE = re.compile(r"[0-9]+")
18
+
19
+
20
+ @dataclass
21
+ class AuditRow:
22
+ path: str
23
+ slug: str
24
+ default_branch: str
25
+ local_branch: str
26
+ workflows: str
27
+ default_branch_requires_pr: str
28
+ force_push_blocked: str
29
+ tag_ruleset: str
30
+ invalid_tags: str
31
+
32
+
33
+ def _requires_pr(rules: list[dict[str, Any]], protection: dict[str, Any]) -> bool:
34
+ rules_pr = any(rule.get("type") == "pull_request" for rule in rules)
35
+ classic_pr = (
36
+ "required_pull_request_reviews" in protection and protection.get("required_pull_request_reviews") is not None
37
+ )
38
+ return rules_pr or classic_pr
39
+
40
+
41
+ def _force_push_blocked(rules: list[dict[str, Any]], protection: dict[str, Any]) -> bool:
42
+ rules_nff = any(rule.get("type") == "non_fast_forward" for rule in rules)
43
+ allow_force_pushes = protection.get("allow_force_pushes")
44
+ classic_force_blocked = isinstance(allow_force_pushes, dict) and allow_force_pushes.get("enabled") is not True
45
+ return rules_nff or classic_force_blocked
46
+
47
+
48
+ def audit_repo(repo: Path, *, root: Path, policy: dict[str, Any]) -> AuditRow:
49
+ pattern = re.compile(release_tag_pattern(policy))
50
+ repo_path = repo.resolve()
51
+ root_path = root.resolve()
52
+ rel = "." if repo_path == root_path else str(repo_path).removeprefix(str(root_path) + "/")
53
+ remote = remote_url(repo)
54
+ slug = normalize_slug(remote)
55
+ invalid_tags = ",".join(
56
+ tag for tag in tags(repo) if not pattern.fullmatch(tag) and not _FLOATING_MAJOR_RE.fullmatch(tag)
57
+ )[:500]
58
+ local_branch = current_branch(repo)
59
+ workflows = workflow_files(repo)
60
+
61
+ if not slug:
62
+ return AuditRow(rel, "", "", local_branch, workflows, "NO_REMOTE", "NO_REMOTE", "NO_REMOTE", invalid_tags)
63
+
64
+ try:
65
+ default = github.default_branch(slug)
66
+ except GitHubAPIError:
67
+ default = ""
68
+
69
+ if not default:
70
+ return AuditRow(rel, slug, "", local_branch, workflows, "API_ERROR", "API_ERROR", "API_ERROR", invalid_tags)
71
+
72
+ # These reads fail closed (§2.7): an ambiguous (auth/5xx/rate-limit) read raises
73
+ # rather than reporting a false "no protection". Degrade the whole row to
74
+ # API_ERROR rather than crash the audit, so one flaky repo doesn't sink the run.
75
+ try:
76
+ rules = github.active_branch_rules(slug, default)
77
+ protection = github.classic_branch_protection(slug, default)
78
+ tag_rulesets = github.tag_ruleset_names(slug)
79
+ except GitHubAPIError:
80
+ err = "API_ERROR"
81
+ return AuditRow(rel, slug, default, local_branch, workflows, err, err, err, invalid_tags)
82
+
83
+ return AuditRow(
84
+ path=rel,
85
+ slug=slug,
86
+ default_branch=default,
87
+ local_branch=local_branch,
88
+ workflows=workflows,
89
+ default_branch_requires_pr="yes" if _requires_pr(rules, protection) else "no",
90
+ force_push_blocked="yes" if _force_push_blocked(rules, protection) else "no",
91
+ tag_ruleset=",".join(tag_rulesets) if tag_rulesets else "no",
92
+ invalid_tags=invalid_tags,
93
+ )
94
+
95
+
96
+ def audit_repos(repos: Iterable[Path], *, root: Path, policy: dict[str, Any]) -> list[AuditRow]:
97
+ return [audit_repo(repo, root=root, policy=policy) for repo in repos]
98
+
99
+
100
+ def discover_and_audit(root: Path, *, policy: dict[str, Any]) -> list[AuditRow]:
101
+ return audit_repos(discover_repos(root), root=root, policy=policy)
102
+
103
+
104
+ def render_tsv(rows: list[AuditRow]) -> str:
105
+ fields = list(AuditRow.__dataclass_fields__.keys())
106
+ lines = ["\t".join(fields)]
107
+ for row in rows:
108
+ values = [str(getattr(row, field)) for field in fields]
109
+ lines.append("\t".join(values))
110
+ return "\n".join(lines)
111
+
112
+
113
+ def render_json(rows: list[AuditRow]) -> str:
114
+ return json.dumps([asdict(row) for row in rows], indent=2)