autospan 0.1.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.
- autospan-0.1.0/CONTRIBUTING.md +13 -0
- autospan-0.1.0/LICENSE +21 -0
- autospan-0.1.0/MANIFEST.in +7 -0
- autospan-0.1.0/PKG-INFO +148 -0
- autospan-0.1.0/README.md +107 -0
- autospan-0.1.0/RELEASING.md +31 -0
- autospan-0.1.0/SECURITY.md +11 -0
- autospan-0.1.0/docs/ARCHITECTURE.md +166 -0
- autospan-0.1.0/docs/CONFIGURATION.md +53 -0
- autospan-0.1.0/docs/CONSOLE.md +149 -0
- autospan-0.1.0/docs/DESIGN.md +52 -0
- autospan-0.1.0/docs/DEVELOPING.md +88 -0
- autospan-0.1.0/docs/EVIDENCE.md +84 -0
- autospan-0.1.0/docs/PLUGIN_AUTHORING.md +254 -0
- autospan-0.1.0/docs/PLUGIN_TRUST.md +25 -0
- autospan-0.1.0/docs/SCENARIO_MANUAL.md +272 -0
- autospan-0.1.0/pyproject.toml +84 -0
- autospan-0.1.0/scripts/check_dist.py +134 -0
- autospan-0.1.0/scripts/check_readme.py +68 -0
- autospan-0.1.0/scripts/verify_install.py +220 -0
- autospan-0.1.0/setup.cfg +4 -0
- autospan-0.1.0/src/autospan/__init__.py +11 -0
- autospan-0.1.0/src/autospan/__main__.py +5 -0
- autospan-0.1.0/src/autospan/_core/__init__.py +1 -0
- autospan-0.1.0/src/autospan/_core/active_claims.py +73 -0
- autospan-0.1.0/src/autospan/_core/config.py +78 -0
- autospan-0.1.0/src/autospan/_core/discovery.py +132 -0
- autospan-0.1.0/src/autospan/_core/evidence_store.py +382 -0
- autospan-0.1.0/src/autospan/_core/graph.py +46 -0
- autospan-0.1.0/src/autospan/_core/handover.py +99 -0
- autospan-0.1.0/src/autospan/_core/host.py +155 -0
- autospan-0.1.0/src/autospan/_core/periodic.py +487 -0
- autospan-0.1.0/src/autospan/_core/planner.py +99 -0
- autospan-0.1.0/src/autospan/_core/provider_discovery.py +71 -0
- autospan-0.1.0/src/autospan/_core/providers.py +124 -0
- autospan-0.1.0/src/autospan/_core/registry.py +53 -0
- autospan-0.1.0/src/autospan/_core/resource_claims.py +25 -0
- autospan-0.1.0/src/autospan/_core/runtime.py +345 -0
- autospan-0.1.0/src/autospan/api/__init__.py +106 -0
- autospan-0.1.0/src/autospan/api/commands.py +420 -0
- autospan-0.1.0/src/autospan/api/component.py +235 -0
- autospan-0.1.0/src/autospan/api/errors.py +29 -0
- autospan-0.1.0/src/autospan/api/evidence.py +136 -0
- autospan-0.1.0/src/autospan/api/frontend.py +82 -0
- autospan-0.1.0/src/autospan/api/gates.py +37 -0
- autospan-0.1.0/src/autospan/api/periodic.py +123 -0
- autospan-0.1.0/src/autospan/api/plugin.py +90 -0
- autospan-0.1.0/src/autospan/api/provider.py +118 -0
- autospan-0.1.0/src/autospan/api/runtime.py +85 -0
- autospan-0.1.0/src/autospan/capabilities/__init__.py +0 -0
- autospan-0.1.0/src/autospan/capabilities/debugger/__init__.py +21 -0
- autospan-0.1.0/src/autospan/capabilities/debugger/contract.py +196 -0
- autospan-0.1.0/src/autospan/capabilities/debugger/fake.py +210 -0
- autospan-0.1.0/src/autospan/capabilities/flasher/__init__.py +11 -0
- autospan-0.1.0/src/autospan/capabilities/flasher/contract.py +57 -0
- autospan-0.1.0/src/autospan/capabilities/flasher/fake.py +34 -0
- autospan-0.1.0/src/autospan/frontends/__init__.py +1 -0
- autospan-0.1.0/src/autospan/frontends/cli.py +273 -0
- autospan-0.1.0/src/autospan/frontends/console.py +140 -0
- autospan-0.1.0/src/autospan/frontends/frontend_host.py +92 -0
- autospan-0.1.0/src/autospan/frontends/pytest_plugin.py +212 -0
- autospan-0.1.0/src/autospan/frontends/scaffold.py +216 -0
- autospan-0.1.0/src/autospan/frontends/test_command.py +226 -0
- autospan-0.1.0/src/autospan/frontends/tui/__init__.py +1 -0
- autospan-0.1.0/src/autospan/frontends/tui/app.py +406 -0
- autospan-0.1.0/src/autospan/frontends/tui/editing.py +38 -0
- autospan-0.1.0/src/autospan/py.typed +0 -0
- autospan-0.1.0/src/autospan/testing/__init__.py +6 -0
- autospan-0.1.0/src/autospan/testing/conformance.py +47 -0
- autospan-0.1.0/src/autospan/testing/harness.py +37 -0
- autospan-0.1.0/src/autospan/testing/plugin.py +68 -0
- autospan-0.1.0/src/autospan.egg-info/PKG-INFO +148 -0
- autospan-0.1.0/src/autospan.egg-info/SOURCES.txt +98 -0
- autospan-0.1.0/src/autospan.egg-info/dependency_links.txt +1 -0
- autospan-0.1.0/src/autospan.egg-info/entry_points.txt +2 -0
- autospan-0.1.0/src/autospan.egg-info/requires.txt +18 -0
- autospan-0.1.0/src/autospan.egg-info/top_level.txt +1 -0
- autospan-0.1.0/tests/test_console.py +185 -0
- autospan-0.1.0/tests/test_console_hardening.py +369 -0
- autospan-0.1.0/tests/test_evidence.py +230 -0
- autospan-0.1.0/tests/test_extension_points.py +652 -0
- autospan-0.1.0/tests/test_graph.py +30 -0
- autospan-0.1.0/tests/test_handover.py +204 -0
- autospan-0.1.0/tests/test_handover_shutdown.py +380 -0
- autospan-0.1.0/tests/test_hardening.py +125 -0
- autospan-0.1.0/tests/test_kernel_independence.py +92 -0
- autospan-0.1.0/tests/test_lifecycle.py +220 -0
- autospan-0.1.0/tests/test_live_claims.py +594 -0
- autospan-0.1.0/tests/test_periodic.py +484 -0
- autospan-0.1.0/tests/test_periodic_shutdown.py +445 -0
- autospan-0.1.0/tests/test_plan.py +62 -0
- autospan-0.1.0/tests/test_plugin_discovery.py +96 -0
- autospan-0.1.0/tests/test_provider_discovery.py +75 -0
- autospan-0.1.0/tests/test_providers.py +185 -0
- autospan-0.1.0/tests/test_public_api.py +72 -0
- autospan-0.1.0/tests/test_resource_claims.py +84 -0
- autospan-0.1.0/tests/test_runtime_reentry.py +277 -0
- autospan-0.1.0/tests/test_scaffold.py +55 -0
- autospan-0.1.0/tests/test_session_runtime.py +224 -0
- autospan-0.1.0/tests/test_tui.py +520 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Install the development dependencies and run the checks in
|
|
4
|
+
[the development guide](docs/DEVELOPING.md).
|
|
5
|
+
|
|
6
|
+
Keep the core independent of protocols, vendors and projects. Driver implementations
|
|
7
|
+
and project configuration belong in separate packages. Add a provider contract only
|
|
8
|
+
when real tool substitution requires it and its semantics can stay generic; see
|
|
9
|
+
[the design principles](docs/DESIGN.md).
|
|
10
|
+
|
|
11
|
+
Include tests for behavior changes and update the relevant public docs. Use synthetic
|
|
12
|
+
fixtures and contribute only material you have the right to license under MIT.
|
|
13
|
+
Keep private configuration, credentials and generated evidence out of commits.
|
autospan-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nidhal Abidi
|
|
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.
|
autospan-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: autospan
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Test automation from hardware to CI
|
|
5
|
+
Author: Nidhal Abidi
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/nidops/autospan
|
|
8
|
+
Project-URL: Documentation, https://github.com/nidops/autospan/blob/master/docs/ARCHITECTURE.md
|
|
9
|
+
Project-URL: Source, https://github.com/nidops/autospan
|
|
10
|
+
Project-URL: Issues, https://github.com/nidops/autospan/issues
|
|
11
|
+
Keywords: testing,test-automation,hardware,pytest,ci,embedded
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Software Development :: Testing
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: PyYAML<7,>=6.0
|
|
26
|
+
Provides-Extra: tui
|
|
27
|
+
Requires-Dist: textual>=0.80; extra == "tui"
|
|
28
|
+
Provides-Extra: test
|
|
29
|
+
Requires-Dist: pytest<10,>=8; extra == "test"
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest<10,>=8; extra == "dev"
|
|
32
|
+
Requires-Dist: textual>=0.80; extra == "dev"
|
|
33
|
+
Requires-Dist: ruff>=0.12; extra == "dev"
|
|
34
|
+
Requires-Dist: mypy>=1.13; extra == "dev"
|
|
35
|
+
Requires-Dist: types-PyYAML; extra == "dev"
|
|
36
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
37
|
+
Requires-Dist: twine<8,>=6.2; extra == "dev"
|
|
38
|
+
Requires-Dist: packaging>=24; extra == "dev"
|
|
39
|
+
Requires-Dist: readme-renderer[md]>=44; extra == "dev"
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
|
|
42
|
+
# AutoSpan
|
|
43
|
+
|
|
44
|
+
Test automation from hardware to CI.
|
|
45
|
+
|
|
46
|
+
AutoSpan plans and runs host-side tests with explicit resource ownership, predictable
|
|
47
|
+
cleanup and evidence. Project plugins supply the configuration, drivers, scenarios
|
|
48
|
+
and commands for a bench. The core stays independent of protocols, vendors and projects.
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
configuration -> project plugin -> runtime plan -> components
|
|
52
|
+
|
|
|
53
|
+
scenarios / console / Python
|
|
54
|
+
|
|
|
55
|
+
events and artifacts
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Quick start
|
|
59
|
+
|
|
60
|
+
Python 3.11 or newer is required. The package is `autospan`; use the `test` and
|
|
61
|
+
`tui` extras for pytest and Textual. Install from this checkout and create a small
|
|
62
|
+
project with an installed smoke scenario:
|
|
63
|
+
|
|
64
|
+
These commands use a POSIX shell. On Windows, create the environment with
|
|
65
|
+
`python -m venv .venv` and activate it with `.venv\Scripts\Activate.ps1` in PowerShell.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
python3 -m venv .venv
|
|
69
|
+
source .venv/bin/activate
|
|
70
|
+
python -m pip install -e '.[test,tui]'
|
|
71
|
+
autospan new sample
|
|
72
|
+
python -m pip install -e './autospan-sample[dev]'
|
|
73
|
+
autospan plan --config autospan-sample/autospan.yaml
|
|
74
|
+
autospan test --config autospan-sample/autospan.yaml -- -q
|
|
75
|
+
autospan console --config autospan-sample/autospan.yaml --plain --exec "sample status"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Interactive Textual use requires the `tui` extra and a TTY; the quick start above
|
|
79
|
+
runs in batch mode.
|
|
80
|
+
|
|
81
|
+
Planning validates configuration, dependencies and claims without opening hardware.
|
|
82
|
+
The sample uses no hardware. For a hardware project, enable the gate explicitly:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
autospan test --config bench.local.yaml -- --hardware -q
|
|
86
|
+
autospan console --config bench.local.yaml --hardware
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
For `test`, arguments after `--` go to pytest. Console and contributed frontends
|
|
90
|
+
accept their gate options before `--`. Installing a plugin does not activate it;
|
|
91
|
+
its name must appear in the configuration.
|
|
92
|
+
|
|
93
|
+
## What the runtime owns
|
|
94
|
+
|
|
95
|
+
- Immutable plans, dependency ordering and resource-claim validation.
|
|
96
|
+
- Component startup, rollback after partial failure and reverse-order teardown.
|
|
97
|
+
- One runtime model shared by hosted pytest, the console and Python frontends.
|
|
98
|
+
- Hardware and destructive gates, with optional project gates.
|
|
99
|
+
- Generic periodic tasks with leases, startup checks and failure reporting.
|
|
100
|
+
- Structured evidence and opaque files with correlation, size and SHA-256 metadata.
|
|
101
|
+
|
|
102
|
+
Plugins use the public `autospan.api` package. `autospan._core` is internal.
|
|
103
|
+
Extensions are trusted Python code; the host is not a sandbox or a real-time scheduler.
|
|
104
|
+
|
|
105
|
+
## Extension points
|
|
106
|
+
|
|
107
|
+
A project plugin owns bench wiring, scenarios, commands and simulation policy:
|
|
108
|
+
|
|
109
|
+
```toml
|
|
110
|
+
[project.entry-points."autospan.plugins"]
|
|
111
|
+
my-project = "my_project.plugin:PLUGIN"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Plugins declare API version `1`. Their component factories open ordinary driver
|
|
115
|
+
libraries and return project facades. Drivers do not need an AutoSpan entry point.
|
|
116
|
+
|
|
117
|
+
Swappable tools such as flashers and debuggers use a separate provider group:
|
|
118
|
+
|
|
119
|
+
```toml
|
|
120
|
+
[project.entry-points."autospan.providers"]
|
|
121
|
+
my-flasher = "my_flasher.autospan:PROVIDER"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
A plan selects a provider by name through `provider_component(...)`. Discovery is
|
|
125
|
+
lazy: `autospan plugins` and `autospan providers` list installed extensions without
|
|
126
|
+
importing them.
|
|
127
|
+
|
|
128
|
+
Commands use `CommandContext` for the live runtime, explicit output and cooperative
|
|
129
|
+
cancellation. The optional `tui` extra supplies history, completion, a command
|
|
130
|
+
picker and log search/export; Quit waits for the active operation. See the
|
|
131
|
+
[console manual](https://github.com/nidops/autospan/blob/master/docs/CONSOLE.md).
|
|
132
|
+
|
|
133
|
+
## Evidence
|
|
134
|
+
|
|
135
|
+
Runs write `events.jsonl` and `manifest.json` under `artifacts/evidence/<run-id>/`.
|
|
136
|
+
Use evidence steps for meaningful actions. Keep high-rate traffic in its recorder
|
|
137
|
+
and attach the resulting file. Worker context must be bound explicitly and must
|
|
138
|
+
match the lifetime of the work being recorded.
|
|
139
|
+
|
|
140
|
+
## Documentation
|
|
141
|
+
|
|
142
|
+
- [Architecture](https://github.com/nidops/autospan/blob/master/docs/ARCHITECTURE.md) and [design principles](https://github.com/nidops/autospan/blob/master/docs/DESIGN.md).
|
|
143
|
+
- [Plugin authoring](https://github.com/nidops/autospan/blob/master/docs/PLUGIN_AUTHORING.md) and [scenario authoring](https://github.com/nidops/autospan/blob/master/docs/SCENARIO_MANUAL.md).
|
|
144
|
+
- [Configuration](https://github.com/nidops/autospan/blob/master/docs/CONFIGURATION.md), [console](https://github.com/nidops/autospan/blob/master/docs/CONSOLE.md) and [evidence](https://github.com/nidops/autospan/blob/master/docs/EVIDENCE.md).
|
|
145
|
+
- [Development](https://github.com/nidops/autospan/blob/master/docs/DEVELOPING.md) and [releasing](https://github.com/nidops/autospan/blob/master/RELEASING.md).
|
|
146
|
+
- [Extension trust](https://github.com/nidops/autospan/blob/master/docs/PLUGIN_TRUST.md) and [security](https://github.com/nidops/autospan/blob/master/SECURITY.md).
|
|
147
|
+
|
|
148
|
+
MIT. See [LICENSE](https://github.com/nidops/autospan/blob/master/LICENSE).
|
autospan-0.1.0/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# AutoSpan
|
|
2
|
+
|
|
3
|
+
Test automation from hardware to CI.
|
|
4
|
+
|
|
5
|
+
AutoSpan plans and runs host-side tests with explicit resource ownership, predictable
|
|
6
|
+
cleanup and evidence. Project plugins supply the configuration, drivers, scenarios
|
|
7
|
+
and commands for a bench. The core stays independent of protocols, vendors and projects.
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
configuration -> project plugin -> runtime plan -> components
|
|
11
|
+
|
|
|
12
|
+
scenarios / console / Python
|
|
13
|
+
|
|
|
14
|
+
events and artifacts
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
Python 3.11 or newer is required. The package is `autospan`; use the `test` and
|
|
20
|
+
`tui` extras for pytest and Textual. Install from this checkout and create a small
|
|
21
|
+
project with an installed smoke scenario:
|
|
22
|
+
|
|
23
|
+
These commands use a POSIX shell. On Windows, create the environment with
|
|
24
|
+
`python -m venv .venv` and activate it with `.venv\Scripts\Activate.ps1` in PowerShell.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
python3 -m venv .venv
|
|
28
|
+
source .venv/bin/activate
|
|
29
|
+
python -m pip install -e '.[test,tui]'
|
|
30
|
+
autospan new sample
|
|
31
|
+
python -m pip install -e './autospan-sample[dev]'
|
|
32
|
+
autospan plan --config autospan-sample/autospan.yaml
|
|
33
|
+
autospan test --config autospan-sample/autospan.yaml -- -q
|
|
34
|
+
autospan console --config autospan-sample/autospan.yaml --plain --exec "sample status"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Interactive Textual use requires the `tui` extra and a TTY; the quick start above
|
|
38
|
+
runs in batch mode.
|
|
39
|
+
|
|
40
|
+
Planning validates configuration, dependencies and claims without opening hardware.
|
|
41
|
+
The sample uses no hardware. For a hardware project, enable the gate explicitly:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
autospan test --config bench.local.yaml -- --hardware -q
|
|
45
|
+
autospan console --config bench.local.yaml --hardware
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
For `test`, arguments after `--` go to pytest. Console and contributed frontends
|
|
49
|
+
accept their gate options before `--`. Installing a plugin does not activate it;
|
|
50
|
+
its name must appear in the configuration.
|
|
51
|
+
|
|
52
|
+
## What the runtime owns
|
|
53
|
+
|
|
54
|
+
- Immutable plans, dependency ordering and resource-claim validation.
|
|
55
|
+
- Component startup, rollback after partial failure and reverse-order teardown.
|
|
56
|
+
- One runtime model shared by hosted pytest, the console and Python frontends.
|
|
57
|
+
- Hardware and destructive gates, with optional project gates.
|
|
58
|
+
- Generic periodic tasks with leases, startup checks and failure reporting.
|
|
59
|
+
- Structured evidence and opaque files with correlation, size and SHA-256 metadata.
|
|
60
|
+
|
|
61
|
+
Plugins use the public `autospan.api` package. `autospan._core` is internal.
|
|
62
|
+
Extensions are trusted Python code; the host is not a sandbox or a real-time scheduler.
|
|
63
|
+
|
|
64
|
+
## Extension points
|
|
65
|
+
|
|
66
|
+
A project plugin owns bench wiring, scenarios, commands and simulation policy:
|
|
67
|
+
|
|
68
|
+
```toml
|
|
69
|
+
[project.entry-points."autospan.plugins"]
|
|
70
|
+
my-project = "my_project.plugin:PLUGIN"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Plugins declare API version `1`. Their component factories open ordinary driver
|
|
74
|
+
libraries and return project facades. Drivers do not need an AutoSpan entry point.
|
|
75
|
+
|
|
76
|
+
Swappable tools such as flashers and debuggers use a separate provider group:
|
|
77
|
+
|
|
78
|
+
```toml
|
|
79
|
+
[project.entry-points."autospan.providers"]
|
|
80
|
+
my-flasher = "my_flasher.autospan:PROVIDER"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
A plan selects a provider by name through `provider_component(...)`. Discovery is
|
|
84
|
+
lazy: `autospan plugins` and `autospan providers` list installed extensions without
|
|
85
|
+
importing them.
|
|
86
|
+
|
|
87
|
+
Commands use `CommandContext` for the live runtime, explicit output and cooperative
|
|
88
|
+
cancellation. The optional `tui` extra supplies history, completion, a command
|
|
89
|
+
picker and log search/export; Quit waits for the active operation. See the
|
|
90
|
+
[console manual](https://github.com/nidops/autospan/blob/master/docs/CONSOLE.md).
|
|
91
|
+
|
|
92
|
+
## Evidence
|
|
93
|
+
|
|
94
|
+
Runs write `events.jsonl` and `manifest.json` under `artifacts/evidence/<run-id>/`.
|
|
95
|
+
Use evidence steps for meaningful actions. Keep high-rate traffic in its recorder
|
|
96
|
+
and attach the resulting file. Worker context must be bound explicitly and must
|
|
97
|
+
match the lifetime of the work being recorded.
|
|
98
|
+
|
|
99
|
+
## Documentation
|
|
100
|
+
|
|
101
|
+
- [Architecture](https://github.com/nidops/autospan/blob/master/docs/ARCHITECTURE.md) and [design principles](https://github.com/nidops/autospan/blob/master/docs/DESIGN.md).
|
|
102
|
+
- [Plugin authoring](https://github.com/nidops/autospan/blob/master/docs/PLUGIN_AUTHORING.md) and [scenario authoring](https://github.com/nidops/autospan/blob/master/docs/SCENARIO_MANUAL.md).
|
|
103
|
+
- [Configuration](https://github.com/nidops/autospan/blob/master/docs/CONFIGURATION.md), [console](https://github.com/nidops/autospan/blob/master/docs/CONSOLE.md) and [evidence](https://github.com/nidops/autospan/blob/master/docs/EVIDENCE.md).
|
|
104
|
+
- [Development](https://github.com/nidops/autospan/blob/master/docs/DEVELOPING.md) and [releasing](https://github.com/nidops/autospan/blob/master/RELEASING.md).
|
|
105
|
+
- [Extension trust](https://github.com/nidops/autospan/blob/master/docs/PLUGIN_TRUST.md) and [security](https://github.com/nidops/autospan/blob/master/SECURITY.md).
|
|
106
|
+
|
|
107
|
+
MIT. See [LICENSE](https://github.com/nidops/autospan/blob/master/LICENSE).
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Releasing AutoSpan
|
|
2
|
+
|
|
3
|
+
Package version lives in `pyproject.toml`; `autospan.__version__` reads installed
|
|
4
|
+
metadata. The plugin API version is separate and is currently `1`.
|
|
5
|
+
|
|
6
|
+
## Setup
|
|
7
|
+
|
|
8
|
+
Configure [trusted publishing](https://docs.pypi.org/trusted-publishers/)
|
|
9
|
+
separately on TestPyPI and PyPI for project `autospan`, repository
|
|
10
|
+
`nidops/autospan`, and workflow `publish.yml`. Use GitHub environments `testpypi`
|
|
11
|
+
and `pypi` respectively, restricted to release tags, with production approval
|
|
12
|
+
where available. For a new project, register a pending publisher; this does not
|
|
13
|
+
reserve the package name. Confirm account ownership and public documentation links.
|
|
14
|
+
|
|
15
|
+
## Release
|
|
16
|
+
|
|
17
|
+
1. Update the package version and documentation.
|
|
18
|
+
2. Run the [development checks](docs/DEVELOPING.md#checks) and
|
|
19
|
+
[distribution checks](docs/DEVELOPING.md#distribution-checks).
|
|
20
|
+
3. From a clean checkout, tag the reviewed `master` commit as `vX.Y.Z` after all
|
|
21
|
+
supported CI jobs pass. Verify the version with
|
|
22
|
+
`python scripts/check_dist.py dist --tag vX.Y.Z`, substituting the actual version.
|
|
23
|
+
4. Push the tag, then manually run **Publish** in GitHub Actions with that tag selected.
|
|
24
|
+
|
|
25
|
+
The workflow reruns CI, uploads verified artifacts to TestPyPI, checks the downloaded
|
|
26
|
+
wheel's hash and installation, then publishes the same artifacts to PyPI and verifies
|
|
27
|
+
again. Pushes alone do not publish. Check the package page after completion.
|
|
28
|
+
|
|
29
|
+
If publication fails, rerun failed jobs in the same run while its `release-dist`
|
|
30
|
+
artifact is available. Never overwrite tags or uploaded files, or hide mismatches
|
|
31
|
+
with `skip-existing`. Changed release contents require a new version.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
Report vulnerabilities privately to the maintainers (use the repository's private
|
|
4
|
+
security advisory feature); do not open a public issue.
|
|
5
|
+
|
|
6
|
+
AutoSpan plugins are trusted Python code and are not sandboxed (see
|
|
7
|
+
`docs/PLUGIN_TRUST.md`). Reports about a malicious or compromised plugin are out
|
|
8
|
+
of scope; reports about the kernel itself (path handling in the evidence store,
|
|
9
|
+
configuration parsing, plan validation, gate bypass) are in scope.
|
|
10
|
+
|
|
11
|
+
Supported versions: the latest `0.x` release.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# AutoSpan architecture
|
|
2
|
+
|
|
3
|
+
## Ownership
|
|
4
|
+
|
|
5
|
+
> AutoSpan owns execution. A project plugin owns project meaning. Drivers are plain libraries. Swappable external tools are providers of narrow kernel contracts.
|
|
6
|
+
|
|
7
|
+
## Runtime model
|
|
8
|
+
|
|
9
|
+
There is one owner per opened runtime. `RuntimeSession` is the internal lifecycle
|
|
10
|
+
owner; `Runtime` is its public live view. Within one Python process, active
|
|
11
|
+
sessions reserve the plan's exclusive/shared resource claims atomically before
|
|
12
|
+
hardware opens, and release claims after teardown or failed startup. This prevents
|
|
13
|
+
function- and session-scoped fixtures from opening the same exclusively claimed
|
|
14
|
+
hardware simultaneously. The registry does **not** coordinate separate processes,
|
|
15
|
+
and different selector aliases still require a common canonical claim identity.
|
|
16
|
+
Shared claims may coexist across sessions, but handover requires all other sessions
|
|
17
|
+
claiming that resource to close first. While an external tool owns it, new claims
|
|
18
|
+
are rejected until reacquisition finishes, including recovery after a failure.
|
|
19
|
+
A project "workspace" is only a directory containing project files/configuration,
|
|
20
|
+
never a second runtime layer. There is no separate `autospan-core` or
|
|
21
|
+
`autospan-workspace` runtime product.
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
config
|
|
25
|
+
↓
|
|
26
|
+
explicitly selected project plugin(s)
|
|
27
|
+
↓
|
|
28
|
+
declaration-only registration
|
|
29
|
+
↓
|
|
30
|
+
side-effect-free RuntimePlan
|
|
31
|
+
↓
|
|
32
|
+
provider resolution + DAG / claims validation
|
|
33
|
+
↓
|
|
34
|
+
dependency-first component acquisition
|
|
35
|
+
↓
|
|
36
|
+
one Runtime view
|
|
37
|
+
├── pytest
|
|
38
|
+
├── console
|
|
39
|
+
└── Python/frontends
|
|
40
|
+
│
|
|
41
|
+
├── runtime-owned periodic scheduler
|
|
42
|
+
└── shared evidence sink
|
|
43
|
+
↓
|
|
44
|
+
stop periodic workers
|
|
45
|
+
↓
|
|
46
|
+
reverse-order component teardown
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Merely installing a project plugin or provider never activates it.
|
|
50
|
+
|
|
51
|
+
Console modes share one dispatcher and the same session:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
plain / batch / Textual -> CommandShell -> CommandContext.runtime -> live components
|
|
55
|
+
| |
|
|
56
|
+
verdict-aware step explicit output / cancellation
|
|
57
|
+
|
|
|
58
|
+
finish/join command -> stop periodic workers -> teardown
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Textual runs one command worker and renders a bounded output queue on its UI
|
|
62
|
+
thread. Busy submissions are rejected. A stop request never substitutes for
|
|
63
|
+
joining that worker before the existing runtime closes.
|
|
64
|
+
|
|
65
|
+
## Package boundary
|
|
66
|
+
|
|
67
|
+
The `autospan` wheel contains orchestration, generic contracts and frontends.
|
|
68
|
+
Protocol/device drivers are separate libraries imported by project packages.
|
|
69
|
+
|
|
70
|
+
The kernel may define a narrow contract for a swappable project-level tool such as a flasher or debugger. Implementations are separate provider packages advertised through `autospan.providers`.
|
|
71
|
+
|
|
72
|
+
## Project composition
|
|
73
|
+
|
|
74
|
+
A project plugin normally plans one project/bench component. Its factory opens the driver libraries it needs inside an `ExitStack` and returns a project facade/rig:
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
project plugin -> compile plan -> project component -> open drivers -> project rig
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Do not explode every driver/client into a kernel component merely because `RuntimePlan` exists. Use separate components when independent lifecycle/dependency/resource ownership actually requires it.
|
|
81
|
+
|
|
82
|
+
## Extension categories
|
|
83
|
+
|
|
84
|
+
AutoSpan has two framework-level extension categories:
|
|
85
|
+
|
|
86
|
+
1. **Project plugin** (`autospan.plugins`) — configuration compilation, project component factories, scenarios, commands, gates, frontends and simulation policy.
|
|
87
|
+
2. **Provider** (`autospan.providers`) — one implementation of a narrow kernel contract such as `flasher` or `debugger`.
|
|
88
|
+
|
|
89
|
+
Drivers use normal Python imports. They have no AutoSpan entry point, project config section or plugin dependency declaration.
|
|
90
|
+
|
|
91
|
+
## Periodic execution
|
|
92
|
+
|
|
93
|
+
Generic recurring execution belongs to the runtime; protocol meaning does not.
|
|
94
|
+
Projects create named periodic tasks from `context.periodic` or `runtime.periodic`.
|
|
95
|
+
Tasks use monotonic scheduling, nested leases, deterministic shutdown, failure
|
|
96
|
+
propagation and basic timing statistics. A lease can optionally wait for one successful
|
|
97
|
+
first callback (`startup_timeout_s`) when a project needs a generic readiness boundary.
|
|
98
|
+
AutoSpan never knows whether the callback is network management, a diagnostic keep-alive,
|
|
99
|
+
serial polling or something else.
|
|
100
|
+
|
|
101
|
+
Periodic workers are stopped before component teardown so a worker cannot continue
|
|
102
|
+
using a driver after its resource has closed. This is host-side orchestration, not a
|
|
103
|
+
hard-real-time scheduler.
|
|
104
|
+
Callbacks must return for shutdown to finish. A slow-stop deadline reports failure;
|
|
105
|
+
the owner still waits for the worker instead of closing its resources underneath it.
|
|
106
|
+
This is intentionally **not** a hard shutdown timeout: Python cannot safely kill a
|
|
107
|
+
blocked thread and revoke its driver's handles. Every periodic callback must use
|
|
108
|
+
finite I/O timeouts and honor its driver's cooperative cancellation policy. If a
|
|
109
|
+
strict stop deadline is required, run the blocking work in a supervised process
|
|
110
|
+
with an explicit termination and ownership-recovery contract.
|
|
111
|
+
|
|
112
|
+
## Evidence
|
|
113
|
+
|
|
114
|
+
Control-plane events are small and structured. High-rate data stays in the owning
|
|
115
|
+
driver/project recorder and is committed as an opaque artifact. Artifact formats are
|
|
116
|
+
open-ended; the evidence store records metadata, correlation, completeness, size and
|
|
117
|
+
hash without parsing the traffic format.
|
|
118
|
+
|
|
119
|
+
## Lifecycle
|
|
120
|
+
|
|
121
|
+
Every component is acquired through a context manager. AutoSpan uses dependency order for startup and reverse order for cleanup. Partial startup failures roll back already-opened components.
|
|
122
|
+
|
|
123
|
+
Runtime entry validates resource claims before reserving resources or opening
|
|
124
|
+
components, including for directly constructed plans. Shutdown rejects new
|
|
125
|
+
handovers, stops and joins periodic workers, then waits for admitted handovers
|
|
126
|
+
to finish reacquisition and diagnostics before closing components. Reservations
|
|
127
|
+
remain held until component cleanup has been attempted, including after errors.
|
|
128
|
+
The session can be entered again once cleanup finishes.
|
|
129
|
+
|
|
130
|
+
Shutdown from inside the session's own handover or periodic callback is rejected
|
|
131
|
+
to avoid waiting on the caller itself. Drivers, handover bodies and evidence
|
|
132
|
+
callbacks must return for cleanup to finish; a blocked hardware call cannot be
|
|
133
|
+
safely cancelled by closing its resources from another thread.
|
|
134
|
+
|
|
135
|
+
## Pytest
|
|
136
|
+
|
|
137
|
+
AutoSpan invokes pytest with explicitly contributed scenario paths and one bridge plugin. Third-party pytest-plugin autoloading is disabled for hosted runs.
|
|
138
|
+
|
|
139
|
+
The function-scoped `runtime` fixture acquires per test for hardware isolation.
|
|
140
|
+
The explicit `session_runtime` fixture acquires once for a shared bench. Use one
|
|
141
|
+
allocation scope per bench; both fixtures use the same owner model.
|
|
142
|
+
|
|
143
|
+
## Gates
|
|
144
|
+
|
|
145
|
+
The host always knows `hardware` and `destructive` (`destructive` implies `hardware`). Project plugins may contribute more. Gates are enforced both on scenarios and on component acquisition, before a gated factory can touch hardware.
|
|
146
|
+
|
|
147
|
+
## Frontends
|
|
148
|
+
|
|
149
|
+
`autospan run NAME` executes a project-contributed frontend using the same plan/runtime owner. A frontend must not create a parallel hardware lifecycle.
|
|
150
|
+
|
|
151
|
+
## Outcome
|
|
152
|
+
|
|
153
|
+
Function-scoped teardown sees the setup/call verdict known at that point; its own
|
|
154
|
+
teardown report arrives later. The session runtime closes after all fixture reports
|
|
155
|
+
and receives the aggregate outcome, including setup and teardown failures. The
|
|
156
|
+
run manifest records the final pytest status. Factories can retain failure-only
|
|
157
|
+
artifacts using `ComponentContext.outcome`.
|
|
158
|
+
|
|
159
|
+
## Non-goals
|
|
160
|
+
|
|
161
|
+
- no runtime Git/package fetching;
|
|
162
|
+
- no plugin dependency graph for drivers;
|
|
163
|
+
- no distributed executor;
|
|
164
|
+
- no hard-real-time guarantee (including periodic workers);
|
|
165
|
+
- no universal transport or device hierarchy;
|
|
166
|
+
- no protocol semantics in the kernel.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
AutoSpan owns only the host section. Each selected project plugin owns and strictly validates its own section.
|
|
4
|
+
|
|
5
|
+
```yaml
|
|
6
|
+
autospan:
|
|
7
|
+
plugins: [my-project]
|
|
8
|
+
|
|
9
|
+
my-project:
|
|
10
|
+
port: sim
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`autospan` currently accepts only `plugins` and `pytest`. Unknown host keys are errors. Project sections are validated by their owning project package; unknown project keys should likewise fail rather than silently default.
|
|
14
|
+
|
|
15
|
+
Project plugins are loaded only when explicitly named. Installing a driver, provider or another project package does not activate it.
|
|
16
|
+
|
|
17
|
+
## Command-line overrides
|
|
18
|
+
|
|
19
|
+
Every config-aware command accepts repeatable `--set dotted.key=value`. Values are parsed as YAML and applied before project loading:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
autospan test --config bench.yaml --set my-project.bench_config=C:/benches/b12.yaml
|
|
23
|
+
autospan plan --config bench.yaml --set autospan.plugins=[my-project]
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Hosted pytest settings
|
|
27
|
+
|
|
28
|
+
`autospan test` never reads an arbitrary project `pytest.ini`/`pyproject.toml`. It writes one `pytest.ini` per run from:
|
|
29
|
+
|
|
30
|
+
1. AutoSpan defaults;
|
|
31
|
+
2. `ScenarioContribution.pytest_ini` defaults from selected projects;
|
|
32
|
+
3. operator `autospan.pytest.ini` overrides.
|
|
33
|
+
|
|
34
|
+
Extra pytest plugins must be explicit because autoload is disabled:
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
autospan:
|
|
38
|
+
plugins: [my-project]
|
|
39
|
+
pytest:
|
|
40
|
+
plugins: [pytest_metadata.plugin]
|
|
41
|
+
ini:
|
|
42
|
+
log_cli_level: DEBUG
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`cache_dir`, `testpaths`, `rootdir` and `confcutdir` are owned by AutoSpan.
|
|
46
|
+
|
|
47
|
+
Planning is side-effect free. Invalid component dependencies, cycles, resource collisions, missing providers, unknown component types and malformed configuration must fail before hardware opens.
|
|
48
|
+
|
|
49
|
+
Relative project paths should be resolved against `PlanBuilder.config_dir`, the directory containing the selected AutoSpan config file.
|
|
50
|
+
|
|
51
|
+
Keep machine-specific settings in ignored files such as `bench.local.yaml`.
|
|
52
|
+
For credentials, store an environment-variable name in reviewed config and resolve
|
|
53
|
+
its value at runtime in project code.
|