versionsec 0.7.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.
Files changed (61) hide show
  1. versionsec-0.7.1/LICENSE +184 -0
  2. versionsec-0.7.1/PKG-INFO +142 -0
  3. versionsec-0.7.1/README.md +108 -0
  4. versionsec-0.7.1/forgeguard/__init__.py +78 -0
  5. versionsec-0.7.1/pyproject.toml +59 -0
  6. versionsec-0.7.1/setup.cfg +4 -0
  7. versionsec-0.7.1/tests/test_audit_reconcile.py +41 -0
  8. versionsec-0.7.1/tests/test_closure.py +164 -0
  9. versionsec-0.7.1/tests/test_config_contract.py +210 -0
  10. versionsec-0.7.1/tests/test_lab_cleanup.py +68 -0
  11. versionsec-0.7.1/tests/test_lab_contract.py +285 -0
  12. versionsec-0.7.1/tests/test_migration_0_7.py +286 -0
  13. versionsec-0.7.1/tests/test_multiforge.py +629 -0
  14. versionsec-0.7.1/tests/test_release_contract.py +139 -0
  15. versionsec-0.7.1/tests/test_release_workflow.py +310 -0
  16. versionsec-0.7.1/tests/test_runner_review.py +324 -0
  17. versionsec-0.7.1/tests/test_sources.py +88 -0
  18. versionsec-0.7.1/tests/test_versionsec.py +1229 -0
  19. versionsec-0.7.1/versionsec/__init__.py +9 -0
  20. versionsec-0.7.1/versionsec/__main__.py +4 -0
  21. versionsec-0.7.1/versionsec/advisories/__init__.py +1 -0
  22. versionsec-0.7.1/versionsec/advisories/catalog/forgejo.json +38 -0
  23. versionsec-0.7.1/versionsec/advisories/catalog/gitea.json +68 -0
  24. versionsec-0.7.1/versionsec/advisories/evaluator.py +83 -0
  25. versionsec-0.7.1/versionsec/advisories/models.py +53 -0
  26. versionsec-0.7.1/versionsec/assessment.py +66 -0
  27. versionsec-0.7.1/versionsec/checks.py +469 -0
  28. versionsec-0.7.1/versionsec/cli.py +375 -0
  29. versionsec-0.7.1/versionsec/client.py +160 -0
  30. versionsec-0.7.1/versionsec/config_review.py +157 -0
  31. versionsec-0.7.1/versionsec/engine.py +333 -0
  32. versionsec-0.7.1/versionsec/exporters/__init__.py +1 -0
  33. versionsec-0.7.1/versionsec/exporters/json.py +12 -0
  34. versionsec-0.7.1/versionsec/exporters/markdown.py +40 -0
  35. versionsec-0.7.1/versionsec/exporters/sarif.py +68 -0
  36. versionsec-0.7.1/versionsec/models.py +79 -0
  37. versionsec-0.7.1/versionsec/output.py +72 -0
  38. versionsec-0.7.1/versionsec/policy.py +25 -0
  39. versionsec-0.7.1/versionsec/providers/__init__.py +1 -0
  40. versionsec-0.7.1/versionsec/providers/base.py +92 -0
  41. versionsec-0.7.1/versionsec/providers/forgejo.py +29 -0
  42. versionsec-0.7.1/versionsec/providers/gitea.py +21 -0
  43. versionsec-0.7.1/versionsec/providers/registry.py +14 -0
  44. versionsec-0.7.1/versionsec/py.typed +1 -0
  45. versionsec-0.7.1/versionsec/report.py +214 -0
  46. versionsec-0.7.1/versionsec/runner_review.py +440 -0
  47. versionsec-0.7.1/versionsec/safety.py +15 -0
  48. versionsec-0.7.1/versionsec/schemas/OASIS_NOTICE.md +79 -0
  49. versionsec-0.7.1/versionsec/schemas/assessment-v1.json +493 -0
  50. versionsec-0.7.1/versionsec/schemas/config-snapshot-v1.json +230 -0
  51. versionsec-0.7.1/versionsec/schemas/runner-snapshot-v1.json +155 -0
  52. versionsec-0.7.1/versionsec/schemas/sarif-2.1.0.json +3389 -0
  53. versionsec-0.7.1/versionsec/scoring.py +96 -0
  54. versionsec-0.7.1/versionsec/urls.py +54 -0
  55. versionsec-0.7.1/versionsec/version.py +14 -0
  56. versionsec-0.7.1/versionsec.egg-info/PKG-INFO +142 -0
  57. versionsec-0.7.1/versionsec.egg-info/SOURCES.txt +59 -0
  58. versionsec-0.7.1/versionsec.egg-info/dependency_links.txt +1 -0
  59. versionsec-0.7.1/versionsec.egg-info/entry_points.txt +3 -0
  60. versionsec-0.7.1/versionsec.egg-info/requires.txt +12 -0
  61. versionsec-0.7.1/versionsec.egg-info/top_level.txt +2 -0
@@ -0,0 +1,184 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 Gexiro Global Enterprises Ltd.
6
+
7
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8
+
9
+ 1. Definitions.
10
+
11
+ "License" shall mean the terms and conditions for use, reproduction, and
12
+ distribution as defined by Sections 1 through 9 of this document.
13
+
14
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright
15
+ owner that is granting the License.
16
+
17
+ "Legal Entity" shall mean the union of the acting entity and all other entities
18
+ that control, are controlled by, or are under common control with that entity.
19
+ For the purposes of this definition, "control" means (i) the power, direct or
20
+ indirect, to cause the direction or management of such entity, whether by
21
+ contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity exercising
25
+ permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications, including
28
+ but not limited to software source code, documentation source, and configuration
29
+ files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical transformation or
32
+ translation of a Source form, including but not limited to compiled object code,
33
+ generated documentation, and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or Object form,
36
+ made available under the License, as indicated by a copyright notice that is
37
+ included in or attached to the work.
38
+
39
+ "Derivative Works" shall mean any work, whether in Source or Object form, that
40
+ is based on (or derived from) the Work and for which the editorial revisions,
41
+ annotations, elaborations, or other modifications represent, as a whole, an
42
+ original work of authorship. For the purposes of this License, Derivative Works
43
+ shall not include works that remain separable from, or merely link (or bind by
44
+ name) to the interfaces of, the Work and Derivative Works thereof.
45
+
46
+ "Contribution" shall mean any work of authorship, including the original version
47
+ of the Work and any modifications or additions to that Work or Derivative Works
48
+ thereof, that is intentionally submitted to Licensor for inclusion in the Work
49
+ by the copyright owner or by an individual or Legal Entity authorized to submit
50
+ on behalf of the copyright owner. For the purposes of this definition,
51
+ "submitted" means any form of electronic, verbal, or written communication sent
52
+ to the Licensor or its representatives, including but not limited to
53
+ communication on electronic mailing lists, source code control systems, and
54
+ issue tracking systems that are managed by, or on behalf of, the Licensor for
55
+ the purpose of discussing and improving the Work, but excluding communication
56
+ that is conspicuously marked or otherwise designated in writing by the copyright
57
+ owner as "Not a Contribution."
58
+
59
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
60
+ of whom a Contribution has been received by Licensor and subsequently
61
+ incorporated within the Work.
62
+
63
+ 2. Grant of Copyright License. Subject to the terms and conditions of this
64
+ License, each Contributor hereby grants to You a perpetual, worldwide,
65
+ non-exclusive, no-charge, royalty-free, irrevocable copyright license to
66
+ reproduce, prepare Derivative Works of, publicly display, publicly perform,
67
+ sublicense, and distribute the Work and such Derivative Works in Source or
68
+ Object form.
69
+
70
+ 3. Grant of Patent License. Subject to the terms and conditions of this License,
71
+ each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
72
+ no-charge, royalty-free, irrevocable (except as stated in this section) patent
73
+ license to make, have made, use, offer to sell, sell, import, and otherwise
74
+ transfer the Work, where such license applies only to those patent claims
75
+ licensable by such Contributor that are necessarily infringed by their
76
+ Contribution(s) alone or by combination of their Contribution(s) with the Work
77
+ to which such Contribution(s) was submitted. If You institute patent litigation
78
+ against any entity (including a cross-claim or counterclaim in a lawsuit)
79
+ alleging that the Work or a Contribution incorporated within the Work
80
+ constitutes direct or contributory patent infringement, then any patent licenses
81
+ granted to You under this License for that Work shall terminate as of the date
82
+ such litigation is filed.
83
+
84
+ 4. Redistribution. You may reproduce and distribute copies of the Work or
85
+ Derivative Works thereof in any medium, with or without modifications, and in
86
+ Source or Object form, provided that You meet the following conditions:
87
+
88
+ (a) You must give any other recipients of the Work or Derivative Works a copy of
89
+ this License; and
90
+
91
+ (b) You must cause any modified files to carry prominent notices stating that
92
+ You changed the files; and
93
+
94
+ (c) You must retain, in the Source form of any Derivative Works that You
95
+ distribute, all copyright, patent, trademark, and attribution notices from the
96
+ Source form of the Work, excluding those notices that do not pertain to any part
97
+ of the Derivative Works; and
98
+
99
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then
100
+ any Derivative Works that You distribute must include a readable copy of the
101
+ attribution notices contained within such NOTICE file, excluding those notices
102
+ that do not pertain to any part of the Derivative Works, in at least one of the
103
+ following places: within a NOTICE text file distributed as part of the
104
+ Derivative Works; within the Source form or documentation, if provided along
105
+ with the Derivative Works; or, within a display generated by the Derivative
106
+ Works, if and wherever such third-party notices normally appear. The contents of
107
+ the NOTICE file are for informational purposes only and do not modify the
108
+ License. You may add Your own attribution notices within Derivative Works that
109
+ You distribute, alongside or as an addendum to the NOTICE text from the Work,
110
+ provided that such additional attribution notices cannot be construed as
111
+ modifying the License.
112
+
113
+ You may add Your own copyright statement to Your modifications and may provide
114
+ additional or different license terms and conditions for use, reproduction, or
115
+ distribution of Your modifications, or for any such Derivative Works as a whole,
116
+ provided Your use, reproduction, and distribution of the Work otherwise complies
117
+ with the conditions stated in this License.
118
+
119
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any
120
+ Contribution intentionally submitted for inclusion in the Work by You to the
121
+ Licensor shall be under the terms and conditions of this License, without any
122
+ additional terms or conditions. Notwithstanding the above, nothing herein shall
123
+ supersede or modify the terms of any separate license agreement you may have
124
+ executed with Licensor regarding such Contributions.
125
+
126
+ 6. Trademarks. This License does not grant permission to use the trade names,
127
+ trademarks, service marks, or product names of the Licensor, except as required
128
+ for reasonable and customary use in describing the origin of the Work and
129
+ reproducing the content of the NOTICE file.
130
+
131
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in
132
+ writing, Licensor provides the Work (and each Contributor provides its
133
+ Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
134
+ KIND, either express or implied, including, without limitation, any warranties or
135
+ conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
136
+ PARTICULAR PURPOSE. You are solely responsible for determining the
137
+ appropriateness of using or redistributing the Work and assume any risks
138
+ associated with Your exercise of permissions under this License.
139
+
140
+ 8. Limitation of Liability. In no event and under no legal theory, whether in
141
+ tort (including negligence), contract, or otherwise, unless required by
142
+ applicable law (such as deliberate and grossly negligent acts) or agreed to in
143
+ writing, shall any Contributor be liable to You for damages, including any
144
+ direct, indirect, special, incidental, or consequential damages of any character
145
+ arising as a result of this License or out of the use or inability to use the
146
+ Work (including but not limited to damages for loss of goodwill, work stoppage,
147
+ computer failure or malfunction, or any and all other commercial damages or
148
+ losses), even if such Contributor has been advised of the possibility of such
149
+ damages.
150
+
151
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or
152
+ Derivative Works thereof, You may choose to offer, and charge a fee for,
153
+ acceptance of support, warranty, indemnity, or other liability obligations
154
+ and/or rights consistent with this License. However, in accepting such
155
+ obligations, You may act only on Your own behalf and on Your sole
156
+ responsibility, not on behalf of any other Contributor, and only if You agree to
157
+ indemnify, defend, and hold each Contributor harmless for any liability incurred
158
+ by, or claims asserted against, such Contributor by reason of your accepting any
159
+ such warranty or additional liability.
160
+
161
+ END OF TERMS AND CONDITIONS
162
+
163
+ APPENDIX: How to apply the Apache License to your work.
164
+
165
+ To apply the Apache License to your work, attach the following boilerplate
166
+ notice, with the fields enclosed by brackets "[]" replaced with your own
167
+ identifying information. Do not include the brackets. The text should be
168
+ enclosed in the appropriate comment syntax for the file format. We also
169
+ recommend that a file or class name and description of purpose be included on
170
+ the same "printed page" as the copyright notice for easier identification within
171
+ third-party archives.
172
+
173
+ Copyright 2026 Gexiro Global Enterprises Ltd.
174
+
175
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
176
+ this file except in compliance with the License. You may obtain a copy of the
177
+ License at
178
+
179
+ http://www.apache.org/licenses/LICENSE-2.0
180
+
181
+ Unless required by applicable law or agreed to in writing, software distributed
182
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
183
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
184
+ specific language governing permissions and limitations under the License.
@@ -0,0 +1,142 @@
1
+ Metadata-Version: 2.4
2
+ Name: versionsec
3
+ Version: 0.7.1
4
+ Summary: Read-only security posture review for one authorized self-hosted Gitea or Forgejo instance, including offline configuration and runner review.
5
+ Author: Gexiro Global Enterprises Ltd
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://versionsec.com
8
+ Project-URL: Repository, https://github.com/gexiro-global/versionsec
9
+ Project-URL: Documentation, https://github.com/gexiro-global/versionsec/tree/main/docs
10
+ Project-URL: Issues, https://github.com/gexiro-global/versionsec/issues
11
+ Project-URL: Changelog, https://github.com/gexiro-global/versionsec/blob/main/CHANGELOG.md
12
+ Keywords: gitea,forgejo,security,posture,self-hosted,sarif,runner
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Security
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.11
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: httpx<1,>=0.27
23
+ Requires-Dist: pydantic<3,>=2
24
+ Requires-Dist: typer<1,>=0.12
25
+ Provides-Extra: dev
26
+ Requires-Dist: build==1.6.1; extra == "dev"
27
+ Requires-Dist: pytest==9.1.1; extra == "dev"
28
+ Requires-Dist: ruff==0.16.6; extra == "dev"
29
+ Requires-Dist: twine==6.2.0; extra == "dev"
30
+ Requires-Dist: pytest-cov==7.1.0; extra == "dev"
31
+ Requires-Dist: jsonschema==4.26.0; extra == "dev"
32
+ Requires-Dist: PyYAML==6.0.3; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ # VersionSec
36
+
37
+ > **VersionSec was formerly ForgeGuard.** Releases up to and including 0.6.0 were published
38
+ > as `forgeguard` and remain available and unchanged. From 0.7.0 the canonical name is
39
+ > VersionSec (`pip install versionsec`). `forgeguard==0.7.1` is a compatibility bridge and
40
+ > the `forgeguard` CLI/import keep working. Stable `FG-*` finding IDs are unchanged.
41
+ > See [MIGRATION.md](MIGRATION.md).
42
+
43
+ [![CI](https://github.com/gexiro-global/versionsec/actions/workflows/ci.yml/badge.svg)](https://github.com/gexiro-global/versionsec/actions/workflows/ci.yml)
44
+ [![PyPI](https://img.shields.io/pypi/v/versionsec.svg)](https://pypi.org/project/versionsec/)
45
+ [![Python](https://img.shields.io/pypi/pyversions/versionsec.svg)](https://pypi.org/project/versionsec/)
46
+ [![License: Apache-2.0](https://img.shields.io/pypi/l/versionsec.svg)](https://github.com/gexiro-global/versionsec/blob/main/LICENSE)
47
+
48
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/gexiro-global/versionsec/badge)](https://scorecard.dev/viewer/?uri=github.com/gexiro-global/versionsec)
49
+ [Security and trust evidence](docs/SECURITY-TRUST.md) documents the project's policies and automated checks. No certification or badge level is claimed.
50
+
51
+ Read-only posture assessment for one explicitly authorized self-hosted Gitea or Forgejo instance, or an explicitly supplied anonymized configuration snapshot.
52
+
53
+ ## VersionSec — 0.7.1
54
+
55
+ The ForgeGuard → VersionSec rebrand. No capability was removed: the separate Gitea or Forgejo providers, read-only live posture assessment, offline configuration review, offline runner review, Markdown/JSON/SARIF exports and deterministic completeness semantics all carry over unchanged. Canonical CLI is `versionsec`, canonical import is `versionsec`; the `forgeguard` CLI and `import forgeguard` continue to work through a compatibility shim that resolves to the same implementation. Machine-readable schema identifiers (`forgeguard.assessment.v1`, `forgeguard.config-snapshot.v1`, `forgeguard.runner-snapshot.v1`) and all `FG-*` finding IDs are deliberately unchanged so existing report consumers keep working. See [MIGRATION.md](MIGRATION.md).
56
+
57
+ ## Control Plane Hardening — 0.6.0
58
+
59
+ Adds an offline runner posture review (`versionsec runner review`) for the trust boundaries that matter most to a Gitea or Forgejo administrator: execution engine isolation, privileged mode, host volume mounts, Docker socket exposure, job network mode, ephemeral registration, and the experimental Forgejo plugin engine. Runner review is zero-network, evaluates only an explicitly supplied `forgeguard.runner-snapshot.v1` snapshot, and never reads runner credentials, `.runner` files, or Docker/registry secrets. Runner qualification targets are Gitea Runner 3.4.2 and Forgejo Runner 13.0.0 / 13.1.0 — see [upstream evidence](docs/UPSTREAM.md) and [runner review](docs/RUNNER_REVIEW.md).
60
+
61
+ ## Multi-Forge Support — 0.5.0
62
+
63
+ Adds Gitea or Forgejo as separate providers, with operator-declared product identity, finite provider-specific advisory catalogs, exposure intent, request profiles, offline configuration review of an explicitly supplied snapshot, and JSON/Markdown/SARIF exports. It does not scan application source code or private artifact contents.
64
+
65
+ Qualification targets are Gitea 1.26.4 / 1.27.3 and Forgejo 15.0.8 / 16.0.4 — these are the exact tested targets, not a universal support promise; see [release notes](docs/RELEASE_CANDIDATE_0_5.md) and the CI evidence linked from the release.
66
+
67
+ ## Install
68
+
69
+ ```bash
70
+ python -m pip install versionsec
71
+ ```
72
+
73
+ Or pin the exact release:
74
+
75
+ ```bash
76
+ python -m pip install versionsec==0.7.1
77
+ ```
78
+
79
+ ## Usage
80
+
81
+ ```bash
82
+ versionsec providers
83
+ versionsec checks
84
+ versionsec scan --url https://git.example.com/team --authorized --product forgejo --profile standard --policy public --dry-run
85
+ versionsec scan --url https://git.example.com/team --authorized --product forgejo --profile standard --policy public --format json
86
+ versionsec config review --snapshot anonymized-snapshot.json --policy private --format json
87
+ versionsec runner review --snapshot runner-snapshot.json --format json
88
+ ```
89
+
90
+ Use minimal for one version request, standard for five bounded existing requests, or extended for those requests plus root. The profiles change scope, not aggressiveness. Exposure intent (public/private/unspecified) is independent; unspecified is the default.
91
+
92
+ The operator declares product identity. Compatible APIs and inventory versions alone do not identify a product. Opposing markers, conflicting versions, unknown syntax and unsupported evidence remain explicitly incomplete. No Gitea advisory is applied to Forgejo.
93
+
94
+ ## Evidence boundaries
95
+
96
+ HTTP 200 on a checked path is only a status observation, not proof of repository readability, private data access or loaded configuration. Public-by-design status observations are informational. Private intent creates a bounded review warning. HTTP 401/403 may support denial on that path only. Errors, redirects, 404, 429, malformed version JSON, timeouts and truncation remain incomplete.
97
+
98
+ Incomplete assessments have null score, N/A grade and assessed=false, even when another check warns. Skipped checks remain listed. Version 2 scores are not comparable with 0.2.2. No score is security certification or a claim of no vulnerabilities.
99
+
100
+ Offline review performs zero requests and evaluates only the supplied snapshot. It supports a closed key list for registration, sign-in, new-repository privacy and product-specific MFA. It never reads app.ini, production files, tokens, databases or private keys. See [config review](docs/CONFIG_REVIEW.md).
101
+
102
+ ## Transport and reports
103
+
104
+ One target, GET only, finite allowlist, no retries or redirects, serial requests, at most 12 requests, 10 seconds each and 60 seconds overall. Responses are streamed with a 256 KiB decompressed limit. HTTPS verifies certificates; --ca-bundle explicitly supplies a private CA. Ambient proxy/CA settings are ignored. HTTP never transmits a token. Anonymous requests do not inherit authentication or cookies.
105
+
106
+ Prefer VERSIONSEC_TOKEN for the optional version-read token. The legacy --token option warns because shell history/process listings may retain it. Reports do not contain the token.
107
+
108
+ Use --format md,json,sarif with --out reports/result.md for separate files. The directory must exist. Existing files, symlinks and collisions are refused, and writes are atomic. Multiple formats require files; single machine-readable stdout is clean.
109
+
110
+ JSON uses forgeguard.assessment.v1 with a packaged schema. SARIF 2.1.0 is schema-validated against frozen OASIS errata01. No source locations are invented. No DevGuard or GitHub Code Scanning importer integration is claimed.
111
+
112
+ ## Documentation
113
+
114
+ - [Migration and exit codes](docs/MIGRATION_0_5.md)
115
+ - [Security model](docs/SECURITY_MODEL.md) and [authorized use](AUTHORIZED_USE.md)
116
+ - [Scoring](docs/SCORING.md), [checks](docs/CHECKS.md), [upstream evidence](docs/UPSTREAM.md)
117
+ - [Provider guide](docs/PROVIDERS.md), [runner review](docs/RUNNER_REVIEW.md) and [integration lab](docs/INTEGRATION_TESTING.md)
118
+ - [Candidate notes](docs/RELEASE_CANDIDATE_0_5.md) and [release checklist](docs/RELEASE_CHECKLIST.md)
119
+
120
+ Historical 0.2.2 before/after examples remain in examples/ for migration context. Current examples use the golden- prefix and are synthetic offline fixtures, not production scans.
121
+
122
+ ## Commercial hardening
123
+
124
+ Gexiro offers a paid Hardening Report for authorized Gitea operators who want human review of bounded evidence, explicit limitations, prioritized findings, and a practical remediation plan.
125
+
126
+ A Remediation Sprint is a separate engagement: scope and acceptance criteria are frozen first, changes begin only after explicit approval, and the result includes before/after verification. Scope expansion, third-party targets, and remote changes require separate written authorization.
127
+
128
+ VersionSec remains usable as a free OSS CLI without a hosted account or control plane. Heavy SaaS and recurring monitoring are not offered at this stage.
129
+
130
+ [Request a scoped VersionSec Hardening Report](mailto:contact@gexiro.com?subject=VersionSec%20Hardening%20Report)
131
+
132
+ ## License
133
+
134
+ Apache-2.0. See [LICENSE](LICENSE).
135
+
136
+ Built and maintained by [Gexiro Global Enterprises Ltd](https://gexiro.com).
137
+
138
+ Part of the [Gexiro open-source toolkit](https://github.com/gexiro-global).
139
+
140
+ VersionSec by Gexiro
141
+
142
+ Not affiliated with Gitea, Forgejo, Codeberg, GitHub, or GitLab.
@@ -0,0 +1,108 @@
1
+ # VersionSec
2
+
3
+ > **VersionSec was formerly ForgeGuard.** Releases up to and including 0.6.0 were published
4
+ > as `forgeguard` and remain available and unchanged. From 0.7.0 the canonical name is
5
+ > VersionSec (`pip install versionsec`). `forgeguard==0.7.1` is a compatibility bridge and
6
+ > the `forgeguard` CLI/import keep working. Stable `FG-*` finding IDs are unchanged.
7
+ > See [MIGRATION.md](MIGRATION.md).
8
+
9
+ [![CI](https://github.com/gexiro-global/versionsec/actions/workflows/ci.yml/badge.svg)](https://github.com/gexiro-global/versionsec/actions/workflows/ci.yml)
10
+ [![PyPI](https://img.shields.io/pypi/v/versionsec.svg)](https://pypi.org/project/versionsec/)
11
+ [![Python](https://img.shields.io/pypi/pyversions/versionsec.svg)](https://pypi.org/project/versionsec/)
12
+ [![License: Apache-2.0](https://img.shields.io/pypi/l/versionsec.svg)](https://github.com/gexiro-global/versionsec/blob/main/LICENSE)
13
+
14
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/gexiro-global/versionsec/badge)](https://scorecard.dev/viewer/?uri=github.com/gexiro-global/versionsec)
15
+ [Security and trust evidence](docs/SECURITY-TRUST.md) documents the project's policies and automated checks. No certification or badge level is claimed.
16
+
17
+ Read-only posture assessment for one explicitly authorized self-hosted Gitea or Forgejo instance, or an explicitly supplied anonymized configuration snapshot.
18
+
19
+ ## VersionSec — 0.7.1
20
+
21
+ The ForgeGuard → VersionSec rebrand. No capability was removed: the separate Gitea or Forgejo providers, read-only live posture assessment, offline configuration review, offline runner review, Markdown/JSON/SARIF exports and deterministic completeness semantics all carry over unchanged. Canonical CLI is `versionsec`, canonical import is `versionsec`; the `forgeguard` CLI and `import forgeguard` continue to work through a compatibility shim that resolves to the same implementation. Machine-readable schema identifiers (`forgeguard.assessment.v1`, `forgeguard.config-snapshot.v1`, `forgeguard.runner-snapshot.v1`) and all `FG-*` finding IDs are deliberately unchanged so existing report consumers keep working. See [MIGRATION.md](MIGRATION.md).
22
+
23
+ ## Control Plane Hardening — 0.6.0
24
+
25
+ Adds an offline runner posture review (`versionsec runner review`) for the trust boundaries that matter most to a Gitea or Forgejo administrator: execution engine isolation, privileged mode, host volume mounts, Docker socket exposure, job network mode, ephemeral registration, and the experimental Forgejo plugin engine. Runner review is zero-network, evaluates only an explicitly supplied `forgeguard.runner-snapshot.v1` snapshot, and never reads runner credentials, `.runner` files, or Docker/registry secrets. Runner qualification targets are Gitea Runner 3.4.2 and Forgejo Runner 13.0.0 / 13.1.0 — see [upstream evidence](docs/UPSTREAM.md) and [runner review](docs/RUNNER_REVIEW.md).
26
+
27
+ ## Multi-Forge Support — 0.5.0
28
+
29
+ Adds Gitea or Forgejo as separate providers, with operator-declared product identity, finite provider-specific advisory catalogs, exposure intent, request profiles, offline configuration review of an explicitly supplied snapshot, and JSON/Markdown/SARIF exports. It does not scan application source code or private artifact contents.
30
+
31
+ Qualification targets are Gitea 1.26.4 / 1.27.3 and Forgejo 15.0.8 / 16.0.4 — these are the exact tested targets, not a universal support promise; see [release notes](docs/RELEASE_CANDIDATE_0_5.md) and the CI evidence linked from the release.
32
+
33
+ ## Install
34
+
35
+ ```bash
36
+ python -m pip install versionsec
37
+ ```
38
+
39
+ Or pin the exact release:
40
+
41
+ ```bash
42
+ python -m pip install versionsec==0.7.1
43
+ ```
44
+
45
+ ## Usage
46
+
47
+ ```bash
48
+ versionsec providers
49
+ versionsec checks
50
+ versionsec scan --url https://git.example.com/team --authorized --product forgejo --profile standard --policy public --dry-run
51
+ versionsec scan --url https://git.example.com/team --authorized --product forgejo --profile standard --policy public --format json
52
+ versionsec config review --snapshot anonymized-snapshot.json --policy private --format json
53
+ versionsec runner review --snapshot runner-snapshot.json --format json
54
+ ```
55
+
56
+ Use minimal for one version request, standard for five bounded existing requests, or extended for those requests plus root. The profiles change scope, not aggressiveness. Exposure intent (public/private/unspecified) is independent; unspecified is the default.
57
+
58
+ The operator declares product identity. Compatible APIs and inventory versions alone do not identify a product. Opposing markers, conflicting versions, unknown syntax and unsupported evidence remain explicitly incomplete. No Gitea advisory is applied to Forgejo.
59
+
60
+ ## Evidence boundaries
61
+
62
+ HTTP 200 on a checked path is only a status observation, not proof of repository readability, private data access or loaded configuration. Public-by-design status observations are informational. Private intent creates a bounded review warning. HTTP 401/403 may support denial on that path only. Errors, redirects, 404, 429, malformed version JSON, timeouts and truncation remain incomplete.
63
+
64
+ Incomplete assessments have null score, N/A grade and assessed=false, even when another check warns. Skipped checks remain listed. Version 2 scores are not comparable with 0.2.2. No score is security certification or a claim of no vulnerabilities.
65
+
66
+ Offline review performs zero requests and evaluates only the supplied snapshot. It supports a closed key list for registration, sign-in, new-repository privacy and product-specific MFA. It never reads app.ini, production files, tokens, databases or private keys. See [config review](docs/CONFIG_REVIEW.md).
67
+
68
+ ## Transport and reports
69
+
70
+ One target, GET only, finite allowlist, no retries or redirects, serial requests, at most 12 requests, 10 seconds each and 60 seconds overall. Responses are streamed with a 256 KiB decompressed limit. HTTPS verifies certificates; --ca-bundle explicitly supplies a private CA. Ambient proxy/CA settings are ignored. HTTP never transmits a token. Anonymous requests do not inherit authentication or cookies.
71
+
72
+ Prefer VERSIONSEC_TOKEN for the optional version-read token. The legacy --token option warns because shell history/process listings may retain it. Reports do not contain the token.
73
+
74
+ Use --format md,json,sarif with --out reports/result.md for separate files. The directory must exist. Existing files, symlinks and collisions are refused, and writes are atomic. Multiple formats require files; single machine-readable stdout is clean.
75
+
76
+ JSON uses forgeguard.assessment.v1 with a packaged schema. SARIF 2.1.0 is schema-validated against frozen OASIS errata01. No source locations are invented. No DevGuard or GitHub Code Scanning importer integration is claimed.
77
+
78
+ ## Documentation
79
+
80
+ - [Migration and exit codes](docs/MIGRATION_0_5.md)
81
+ - [Security model](docs/SECURITY_MODEL.md) and [authorized use](AUTHORIZED_USE.md)
82
+ - [Scoring](docs/SCORING.md), [checks](docs/CHECKS.md), [upstream evidence](docs/UPSTREAM.md)
83
+ - [Provider guide](docs/PROVIDERS.md), [runner review](docs/RUNNER_REVIEW.md) and [integration lab](docs/INTEGRATION_TESTING.md)
84
+ - [Candidate notes](docs/RELEASE_CANDIDATE_0_5.md) and [release checklist](docs/RELEASE_CHECKLIST.md)
85
+
86
+ Historical 0.2.2 before/after examples remain in examples/ for migration context. Current examples use the golden- prefix and are synthetic offline fixtures, not production scans.
87
+
88
+ ## Commercial hardening
89
+
90
+ Gexiro offers a paid Hardening Report for authorized Gitea operators who want human review of bounded evidence, explicit limitations, prioritized findings, and a practical remediation plan.
91
+
92
+ A Remediation Sprint is a separate engagement: scope and acceptance criteria are frozen first, changes begin only after explicit approval, and the result includes before/after verification. Scope expansion, third-party targets, and remote changes require separate written authorization.
93
+
94
+ VersionSec remains usable as a free OSS CLI without a hosted account or control plane. Heavy SaaS and recurring monitoring are not offered at this stage.
95
+
96
+ [Request a scoped VersionSec Hardening Report](mailto:contact@gexiro.com?subject=VersionSec%20Hardening%20Report)
97
+
98
+ ## License
99
+
100
+ Apache-2.0. See [LICENSE](LICENSE).
101
+
102
+ Built and maintained by [Gexiro Global Enterprises Ltd](https://gexiro.com).
103
+
104
+ Part of the [Gexiro open-source toolkit](https://github.com/gexiro-global).
105
+
106
+ VersionSec by Gexiro
107
+
108
+ Not affiliated with Gitea, Forgejo, Codeberg, GitHub, or GitLab.
@@ -0,0 +1,78 @@
1
+ """Compatibility shim: ForgeGuard was renamed to VersionSec in 0.7.0.
2
+
3
+ ``import forgeguard`` and ``import forgeguard.cli`` keep working and resolve to the
4
+ canonical ``versionsec`` implementation. There is no second implementation here: every
5
+ name is an alias of the canonical module object, so the two import paths cannot drift.
6
+
7
+ Canonical from 0.7.0 onward::
8
+
9
+ python -m pip install versionsec
10
+ import versionsec
11
+
12
+ The legacy path stays quiet on purpose - it emits no warning to stdout or stderr, so
13
+ existing automation does not break. See MIGRATION.md.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import importlib
19
+ import sys
20
+
21
+ import versionsec as _versionsec
22
+
23
+ __version__ = _versionsec.__version__
24
+ __all__ = list(getattr(_versionsec, "__all__", []))
25
+
26
+ _SUBMODULES = (
27
+ "advisories",
28
+ "advisories.evaluator",
29
+ "advisories.models",
30
+ "assessment",
31
+ "checks",
32
+ "cli",
33
+ "client",
34
+ "config_review",
35
+ "engine",
36
+ "exporters",
37
+ "exporters.json",
38
+ "exporters.markdown",
39
+ "exporters.sarif",
40
+ "models",
41
+ "output",
42
+ "policy",
43
+ "providers",
44
+ "providers.base",
45
+ "providers.forgejo",
46
+ "providers.gitea",
47
+ "providers.registry",
48
+ "report",
49
+ "runner_review",
50
+ "safety",
51
+ "scoring",
52
+ "urls",
53
+ "version",
54
+ )
55
+
56
+ # Register each canonical submodule under the legacy name as well, so that the
57
+ # statement form ``import forgeguard.cli`` resolves without a second implementation.
58
+ for _name in _SUBMODULES:
59
+ try:
60
+ _module = importlib.import_module(f"versionsec.{_name}")
61
+ except ModuleNotFoundError: # pragma: no cover - defensive
62
+ continue
63
+ sys.modules[f"{__name__}.{_name}"] = _module
64
+ if "." not in _name:
65
+ globals()[_name] = _module
66
+ del _name, _module
67
+
68
+
69
+ def __getattr__(name: str):
70
+ """Any remaining attribute resolves against the canonical package."""
71
+ try:
72
+ return getattr(_versionsec, name)
73
+ except AttributeError as exc:
74
+ raise AttributeError(name) from exc
75
+
76
+
77
+ def __dir__():
78
+ return sorted(set(dir(_versionsec)) | {n for n in _SUBMODULES if "." not in n})
@@ -0,0 +1,59 @@
1
+ [build-system]
2
+ requires = ["setuptools==84.0.0", "wheel==0.48.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "versionsec"
7
+ version = "0.7.1"
8
+ description = "Read-only security posture review for one authorized self-hosted Gitea or Forgejo instance, including offline configuration and runner review."
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "Apache-2.0"
12
+ license-files = ["LICENSE"]
13
+ authors = [
14
+ {name = "Gexiro Global Enterprises Ltd"}
15
+ ]
16
+ keywords = ["gitea", "forgejo", "security", "posture", "self-hosted", "sarif", "runner"]
17
+ classifiers = [
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Topic :: Security",
23
+ "Typing :: Typed",
24
+ ]
25
+ dependencies = [
26
+ "httpx>=0.27,<1",
27
+ "pydantic>=2,<3",
28
+ "typer>=0.12,<1"
29
+ ]
30
+
31
+ [project.urls]
32
+ Homepage = "https://versionsec.com"
33
+ Repository = "https://github.com/gexiro-global/versionsec"
34
+ Documentation = "https://github.com/gexiro-global/versionsec/tree/main/docs"
35
+ Issues = "https://github.com/gexiro-global/versionsec/issues"
36
+ Changelog = "https://github.com/gexiro-global/versionsec/blob/main/CHANGELOG.md"
37
+
38
+ [project.scripts]
39
+ versionsec = "versionsec.cli:main"
40
+ # Compatibility alias retained for the ForgeGuard -> VersionSec migration; see MIGRATION.md.
41
+ forgeguard = "versionsec.cli:main"
42
+
43
+ [project.optional-dependencies]
44
+ dev = [
45
+ "build==1.6.1",
46
+ "pytest==9.1.1",
47
+ "ruff==0.16.6",
48
+ "twine==6.2.0",
49
+ "pytest-cov==7.1.0",
50
+ "jsonschema==4.26.0",
51
+ "PyYAML==6.0.3",
52
+ ]
53
+
54
+ [tool.setuptools.packages.find]
55
+ # forgeguard* is the import-compatibility shim, not a second implementation.
56
+ include = ["versionsec*", "forgeguard*"]
57
+
58
+ [tool.setuptools.package-data]
59
+ versionsec = ["py.typed", "schemas/*.json", "schemas/*.md", "advisories/catalog/*.json"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,41 @@
1
+ """E-FINAL: inventory/audit reconciliation is a set comparison, not a count."""
2
+
3
+ from tools.audit_reconcile import normalize, reconcile
4
+
5
+
6
+ def test_full_coverage_ok():
7
+ inv = {"httpx": "0.28.1", "pydantic": "2.13.5", "typer": "0.27.2"}
8
+ r = reconcile(inv, dict(inv))
9
+ assert r["ok"] and not r["missing"] and not r["version_mismatches"]
10
+
11
+
12
+ def test_detects_removed_record():
13
+ inv = {"httpx": "0.28.1", "setuptools": "84.0.0", "wheel": "0.48.0"}
14
+ audited = {"httpx": "0.28.1"} # tooling silently dropped
15
+ r = reconcile(inv, audited)
16
+ assert r["missing"] == ["setuptools", "wheel"]
17
+ assert not r["ok"]
18
+
19
+
20
+ def test_detects_version_swap_at_same_count():
21
+ inv = {"packaging": "26.3", "httpx": "0.28.1"}
22
+ audited = {"packaging": "25.0", "httpx": "0.28.1"} # same count, wrong version
23
+ r = reconcile(inv, audited)
24
+ assert len(inv) == len(audited)
25
+ assert r["version_mismatches"] == [
26
+ {"package": "packaging", "inventory": "26.3", "audited": "25.0"}
27
+ ]
28
+ assert not r["ok"]
29
+
30
+
31
+ def test_detects_unexpected_extra():
32
+ r = reconcile({"httpx": "0.28.1"}, {"httpx": "0.28.1", "evil": "1.0"})
33
+ assert r["unexpected"] == ["evil"]
34
+ assert not r["ok"]
35
+
36
+
37
+ def test_name_normalisation():
38
+ assert normalize("PyYAML") == "pyyaml"
39
+ assert normalize("typing_extensions") == "typing-extensions"
40
+ r = reconcile({"PyYAML": "6.0.3"}, {"pyyaml": "6.0.3"})
41
+ assert r["ok"]