fabricgate 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.
- fabricgate-0.1.0/.editorconfig +25 -0
- fabricgate-0.1.0/.github/dependabot.yml +10 -0
- fabricgate-0.1.0/.github/workflows/ci.yaml +94 -0
- fabricgate-0.1.0/.github/workflows/release.yaml +165 -0
- fabricgate-0.1.0/.gitignore +68 -0
- fabricgate-0.1.0/.python-version +1 -0
- fabricgate-0.1.0/CONTRIBUTING.md +52 -0
- fabricgate-0.1.0/LICENSE +21 -0
- fabricgate-0.1.0/PKG-INFO +122 -0
- fabricgate-0.1.0/README.md +88 -0
- fabricgate-0.1.0/SECURITY.md +44 -0
- fabricgate-0.1.0/docs/contracts/CHANGELOG.md +85 -0
- fabricgate-0.1.0/docs/contracts/openapi.json +5963 -0
- fabricgate-0.1.0/docs/contracts/openapi.yaml +3968 -0
- fabricgate-0.1.0/docs/contracts/schemas/board-db.schema.json +154 -0
- fabricgate-0.1.0/docs/contracts/schemas/design-index.schema.json +221 -0
- fabricgate-0.1.0/docs/contracts/schemas/platform-manifest.schema.json +948 -0
- fabricgate-0.1.0/docs/specs/README.md +11 -0
- fabricgate-0.1.0/docs/specs/board-db-schema.md +198 -0
- fabricgate-0.1.0/docs/specs/cli-specification.md +1506 -0
- fabricgate-0.1.0/docs/specs/client-behavior.md +288 -0
- fabricgate-0.1.0/docs/specs/design-index-schema.md +282 -0
- fabricgate-0.1.0/docs/specs/platform-manifest-schema.md +679 -0
- fabricgate-0.1.0/pyproject.toml +102 -0
- fabricgate-0.1.0/scripts/extract_schemas.py +76 -0
- fabricgate-0.1.0/src/fabricgate/_version.py +4 -0
- fabricgate-0.1.0/src/fabricgate/cli/__init__.py +1 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/__init__.py +1 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/build.py +359 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/deprecate.py +77 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/diff.py +123 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/info.py +42 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/license_check.py +76 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/list_cmd.py +44 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/login.py +41 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/pull.py +80 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/push.py +162 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/quota.py +66 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/search.py +58 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/stats.py +95 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/token.py +106 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/verify.py +38 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/watch.py +58 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/webhook.py +166 -0
- fabricgate-0.1.0/src/fabricgate/cli/commands/yank.py +49 -0
- fabricgate-0.1.0/src/fabricgate/cli/exit_codes.py +28 -0
- fabricgate-0.1.0/src/fabricgate/cli/main.py +83 -0
- fabricgate-0.1.0/src/fabricgate/client/__init__.py +44 -0
- fabricgate-0.1.0/src/fabricgate/client/auth.py +108 -0
- fabricgate-0.1.0/src/fabricgate/client/cache.py +97 -0
- fabricgate-0.1.0/src/fabricgate/client/config.py +52 -0
- fabricgate-0.1.0/src/fabricgate/client/errors.py +27 -0
- fabricgate-0.1.0/src/fabricgate/client/publisher.py +147 -0
- fabricgate-0.1.0/src/fabricgate/client/puller.py +382 -0
- fabricgate-0.1.0/src/fabricgate/client/registry_client.py +649 -0
- fabricgate-0.1.0/src/fabricgate/client/resolver.py +93 -0
- fabricgate-0.1.0/src/fabricgate/client/validator.py +30 -0
- fabricgate-0.1.0/src/fabricgate/data/__init__.py +0 -0
- fabricgate-0.1.0/src/fabricgate/data/board-db/.gitkeep +0 -0
- fabricgate-0.1.0/src/fabricgate/data/board-db/official.yaml +79 -0
- fabricgate-0.1.0/src/fabricgate/models/__init__.py +10 -0
- fabricgate-0.1.0/src/fabricgate/models/api/__init__.py +1 -0
- fabricgate-0.1.0/src/fabricgate/models/api/errors.py +74 -0
- fabricgate-0.1.0/src/fabricgate/models/api/members.py +49 -0
- fabricgate-0.1.0/src/fabricgate/models/api/requests.py +211 -0
- fabricgate-0.1.0/src/fabricgate/models/api/responses.py +672 -0
- fabricgate-0.1.0/src/fabricgate/models/board_db.py +210 -0
- fabricgate-0.1.0/src/fabricgate/models/cli.py +312 -0
- fabricgate-0.1.0/src/fabricgate/models/common.py +390 -0
- fabricgate-0.1.0/src/fabricgate/models/design_index.py +110 -0
- fabricgate-0.1.0/src/fabricgate/models/platform_manifest.py +394 -0
- fabricgate-0.1.0/src/fabricgate/py.typed +1 -0
- fabricgate-0.1.0/src/fabricgate/sdk/__init__.py +5 -0
- fabricgate-0.1.0/src/fabricgate/sdk/_helpers.py +218 -0
- fabricgate-0.1.0/src/fabricgate/sdk/api.py +72 -0
- fabricgate-0.1.0/src/fabricgate/sdk/auth.py +231 -0
- fabricgate-0.1.0/src/fabricgate/sdk/designs/__init__.py +35 -0
- fabricgate-0.1.0/src/fabricgate/sdk/designs/diff.py +25 -0
- fabricgate-0.1.0/src/fabricgate/sdk/designs/license.py +69 -0
- fabricgate-0.1.0/src/fabricgate/sdk/designs/lifecycle.py +198 -0
- fabricgate-0.1.0/src/fabricgate/sdk/designs/pull.py +142 -0
- fabricgate-0.1.0/src/fabricgate/sdk/designs/push.py +163 -0
- fabricgate-0.1.0/src/fabricgate/sdk/designs/quota.py +41 -0
- fabricgate-0.1.0/src/fabricgate/sdk/designs/search.py +69 -0
- fabricgate-0.1.0/src/fabricgate/sdk/designs/stats.py +105 -0
- fabricgate-0.1.0/src/fabricgate/sdk/designs/watch.py +101 -0
- fabricgate-0.1.0/src/fabricgate/sdk/hwh_parser.py +152 -0
- fabricgate-0.1.0/src/fabricgate/sdk/webhooks.py +211 -0
- fabricgate-0.1.0/tests/__init__.py +0 -0
- fabricgate-0.1.0/tests/fixtures/__init__.py +5 -0
- fabricgate-0.1.0/tests/fixtures/demo_adder_design_index.yaml +23 -0
- fabricgate-0.1.0/tests/fixtures/demo_adder_platform_manifest.yaml +30 -0
- fabricgate-0.1.0/tests/fixtures/factory.py +63 -0
- fabricgate-0.1.0/tests/fixtures/hello_design_index.yaml +16 -0
- fabricgate-0.1.0/tests/fixtures/hello_platform_manifest.yaml +21 -0
- fabricgate-0.1.0/tests/fixtures/pynq_z2_shell_design_index.yaml +17 -0
- fabricgate-0.1.0/tests/fixtures/pynq_z2_shell_platform_manifest.yaml +25 -0
- fabricgate-0.1.0/tests/fixtures/sample_index.yaml +26 -0
- fabricgate-0.1.0/tests/fixtures/sample_manifest.yaml +21 -0
- fabricgate-0.1.0/tests/unit/__init__.py +0 -0
- fabricgate-0.1.0/tests/unit/test_cli.py +2822 -0
- fabricgate-0.1.0/tests/unit/test_client.py +566 -0
- fabricgate-0.1.0/tests/unit/test_client_errors.py +51 -0
- fabricgate-0.1.0/tests/unit/test_client_protocol.py +55 -0
- fabricgate-0.1.0/tests/unit/test_contract_schemas.py +109 -0
- fabricgate-0.1.0/tests/unit/test_extract_schemas.py +40 -0
- fabricgate-0.1.0/tests/unit/test_hwh_parser.py +617 -0
- fabricgate-0.1.0/tests/unit/test_models.py +2636 -0
- fabricgate-0.1.0/tests/unit/test_registry_client.py +993 -0
- fabricgate-0.1.0/tests/unit/test_release_hygiene.py +81 -0
- fabricgate-0.1.0/tests/unit/test_sdk.py +3970 -0
- fabricgate-0.1.0/tests/unit/test_watch.py +275 -0
- fabricgate-0.1.0/uv.lock +1873 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
end_of_line = lf
|
|
6
|
+
insert_final_newline = true
|
|
7
|
+
trim_trailing_whitespace = true
|
|
8
|
+
indent_style = space
|
|
9
|
+
indent_size = 4
|
|
10
|
+
|
|
11
|
+
[*.{yaml,yml,json,toml}]
|
|
12
|
+
indent_size = 2
|
|
13
|
+
|
|
14
|
+
[*.{js,jsx,ts,tsx,css}]
|
|
15
|
+
indent_size = 2
|
|
16
|
+
|
|
17
|
+
[*.md]
|
|
18
|
+
trim_trailing_whitespace = false
|
|
19
|
+
|
|
20
|
+
[Makefile]
|
|
21
|
+
indent_style = tab
|
|
22
|
+
|
|
23
|
+
[Dockerfile*]
|
|
24
|
+
indent_style = space
|
|
25
|
+
indent_size = 4
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
# Public CI: lint, type-check, unit tests, build + publication-boundary
|
|
4
|
+
# check, dependency audit. No secrets are used anywhere in this workflow.
|
|
5
|
+
on:
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master]
|
|
8
|
+
push:
|
|
9
|
+
branches: [master]
|
|
10
|
+
workflow_call:
|
|
11
|
+
inputs:
|
|
12
|
+
force_all:
|
|
13
|
+
description: "Kept for release.yaml compatibility; every job always runs here"
|
|
14
|
+
type: boolean
|
|
15
|
+
default: false
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
check:
|
|
22
|
+
name: Check (ruff / mypy)
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
26
|
+
- uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
|
|
27
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
28
|
+
with:
|
|
29
|
+
python-version-file: ".python-version"
|
|
30
|
+
- run: uv sync --frozen
|
|
31
|
+
- run: uv run ruff check .
|
|
32
|
+
- run: uv run ruff format --check .
|
|
33
|
+
- run: uv run mypy src
|
|
34
|
+
|
|
35
|
+
test:
|
|
36
|
+
name: Test
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
strategy:
|
|
39
|
+
matrix:
|
|
40
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
41
|
+
env:
|
|
42
|
+
# Overrides .python-version so both uv sync and uv run use the matrix
|
|
43
|
+
# interpreter; otherwise uv run re-creates the venv with 3.11 and drops
|
|
44
|
+
# the dev group.
|
|
45
|
+
UV_PYTHON: ${{ matrix.python-version }}
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
48
|
+
- uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
|
|
49
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
50
|
+
with:
|
|
51
|
+
python-version: ${{ matrix.python-version }}
|
|
52
|
+
- run: uv sync --frozen
|
|
53
|
+
- run: uv run pytest -q --cov=fabricgate --cov-report=term-missing
|
|
54
|
+
|
|
55
|
+
build:
|
|
56
|
+
name: Build & boundary check
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
60
|
+
- uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
|
|
61
|
+
- run: uv build
|
|
62
|
+
- name: Enforce publication boundary (no registry code in wheel/sdist)
|
|
63
|
+
run: |
|
|
64
|
+
set -euo pipefail
|
|
65
|
+
for whl in dist/*.whl; do
|
|
66
|
+
python3 -m zipfile --list "$whl" | grep -q "fabricgate/registry/" && { echo "::error::$whl contains fabricgate/registry/"; exit 1; }
|
|
67
|
+
done
|
|
68
|
+
for sdist in dist/*.tar.gz; do
|
|
69
|
+
tar -tzf "$sdist" | grep -q "fabricgate/registry/" && { echo "::error::$sdist contains fabricgate/registry/"; exit 1; }
|
|
70
|
+
done
|
|
71
|
+
echo "boundary OK"
|
|
72
|
+
- name: Smoke-install the wheel
|
|
73
|
+
run: |
|
|
74
|
+
python3 -m venv /tmp/smoke && /tmp/smoke/bin/pip install -q dist/*.whl
|
|
75
|
+
/tmp/smoke/bin/fabricgate --version && /tmp/smoke/bin/fgate --help > /dev/null
|
|
76
|
+
|
|
77
|
+
audit:
|
|
78
|
+
name: Dependency audit
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
steps:
|
|
81
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
82
|
+
- uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
|
|
83
|
+
- run: uv sync --frozen
|
|
84
|
+
- run: uv run pip-audit
|
|
85
|
+
|
|
86
|
+
ci-success:
|
|
87
|
+
name: CI Success
|
|
88
|
+
if: always()
|
|
89
|
+
needs: [check, test, build, audit]
|
|
90
|
+
runs-on: ubuntu-latest
|
|
91
|
+
steps:
|
|
92
|
+
- run: |
|
|
93
|
+
echo '${{ toJSON(needs) }}' | grep -qE '"result": "(failure|cancelled)"' && exit 1
|
|
94
|
+
echo "all green"
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Triggers:
|
|
4
|
+
# - push of a stable vX.Y.Z tag: full release (PyPI + attestation + GitHub Release)
|
|
5
|
+
# Pre-release / staging tags (v0.1.0-staging.N) are handled by cd.yaml only;
|
|
6
|
+
# they would always fail the version guard below, so Release ignores them.
|
|
7
|
+
# - workflow_dispatch: TestPyPI dry-run (no GitHub Release)
|
|
8
|
+
#
|
|
9
|
+
# Prerequisites (one-time, human):
|
|
10
|
+
# - PyPI / TestPyPI Trusted Publisher registered for this repo
|
|
11
|
+
# (workflow=release.yaml, environment=pypi / testpypi)
|
|
12
|
+
# - GitHub environments `pypi` and `testpypi` created
|
|
13
|
+
on:
|
|
14
|
+
push:
|
|
15
|
+
tags:
|
|
16
|
+
- "v[0-9]+.[0-9]+.[0-9]+"
|
|
17
|
+
workflow_dispatch: # TestPyPI dry-run
|
|
18
|
+
|
|
19
|
+
concurrency:
|
|
20
|
+
group: release-${{ github.ref_name }}
|
|
21
|
+
cancel-in-progress: false
|
|
22
|
+
|
|
23
|
+
permissions:
|
|
24
|
+
contents: read
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
ci:
|
|
28
|
+
name: CI Gate
|
|
29
|
+
# ci.yaml declares `pull-requests: read`; a called workflow cannot request
|
|
30
|
+
# more than the calling job holds, so grant it explicitly here. Without
|
|
31
|
+
# this GitHub refuses to start the run at all (startup_failure, 0 jobs).
|
|
32
|
+
permissions:
|
|
33
|
+
contents: read
|
|
34
|
+
pull-requests: read
|
|
35
|
+
uses: ./.github/workflows/ci.yaml
|
|
36
|
+
with:
|
|
37
|
+
# In reusable workflows the `github` context is the caller's, so
|
|
38
|
+
# ci.yaml's paths-filter sees an empty diff on tag pushes and would
|
|
39
|
+
# skip every job. Force the full gate instead.
|
|
40
|
+
force_all: true
|
|
41
|
+
secrets: inherit
|
|
42
|
+
|
|
43
|
+
build:
|
|
44
|
+
name: Build public package
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
needs: [ci]
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
49
|
+
|
|
50
|
+
- name: Install uv
|
|
51
|
+
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
|
|
52
|
+
|
|
53
|
+
- name: Verify tag matches package version
|
|
54
|
+
if: github.event_name == 'push'
|
|
55
|
+
run: |
|
|
56
|
+
TAG_VERSION="${GITHUB_REF_NAME#v}"
|
|
57
|
+
PKG_VERSION=$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
|
|
58
|
+
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
|
|
59
|
+
echo "::error::tag v$TAG_VERSION != pyproject.toml version $PKG_VERSION"
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
- name: Use a unique dev version for TestPyPI dry-runs
|
|
64
|
+
# TestPyPI never lets a deleted filename be reused, so every dry-run
|
|
65
|
+
# publishes <version>.dev<run_number>. Tag pushes keep the real version.
|
|
66
|
+
if: github.event_name == 'workflow_dispatch'
|
|
67
|
+
run: |
|
|
68
|
+
set -euo pipefail
|
|
69
|
+
BASE=$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
|
|
70
|
+
DEV="${BASE}.dev${GITHUB_RUN_NUMBER}"
|
|
71
|
+
uv version --frozen "$DEV"
|
|
72
|
+
sed -i "s/^__version__ = \".*\"$/__version__ = \"${DEV}\"/" src/fabricgate/_version.py
|
|
73
|
+
grep -q "\"${DEV}\"" src/fabricgate/_version.py
|
|
74
|
+
echo "dry-run version: ${DEV}"
|
|
75
|
+
|
|
76
|
+
- name: Build
|
|
77
|
+
run: uv build
|
|
78
|
+
|
|
79
|
+
- name: Enforce publication boundary (no registry code in wheel/sdist)
|
|
80
|
+
# Capture listings before grepping so a failed listing (missing
|
|
81
|
+
# artifact, unreadable archive) fails the step instead of being
|
|
82
|
+
# swallowed by the pipe inside the `if` condition.
|
|
83
|
+
run: |
|
|
84
|
+
set -euo pipefail
|
|
85
|
+
shopt -s nullglob
|
|
86
|
+
wheels=(dist/*.whl)
|
|
87
|
+
sdists=(dist/*.tar.gz)
|
|
88
|
+
if [ "${#wheels[@]}" -eq 0 ] || [ "${#sdists[@]}" -eq 0 ]; then
|
|
89
|
+
echo "::error::expected at least one wheel and one sdist in dist/ (found ${#wheels[@]} wheel(s), ${#sdists[@]} sdist(s))"
|
|
90
|
+
exit 1
|
|
91
|
+
fi
|
|
92
|
+
for whl in "${wheels[@]}"; do
|
|
93
|
+
listing=$(python3 -m zipfile --list "$whl")
|
|
94
|
+
if grep -q "fabricgate/registry/" <<<"$listing"; then
|
|
95
|
+
echo "::error::wheel $whl contains fabricgate/registry/ — distribution-policy P-2 violation"
|
|
96
|
+
exit 1
|
|
97
|
+
fi
|
|
98
|
+
done
|
|
99
|
+
for sdist in "${sdists[@]}"; do
|
|
100
|
+
listing=$(tar -tzf "$sdist")
|
|
101
|
+
if grep -q "fabricgate/registry/" <<<"$listing"; then
|
|
102
|
+
echo "::error::sdist $sdist contains fabricgate/registry/ — distribution-policy P-2 violation"
|
|
103
|
+
exit 1
|
|
104
|
+
fi
|
|
105
|
+
done
|
|
106
|
+
|
|
107
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
108
|
+
with:
|
|
109
|
+
name: dist
|
|
110
|
+
path: dist/
|
|
111
|
+
|
|
112
|
+
publish:
|
|
113
|
+
name: Publish to ${{ github.event_name == 'workflow_dispatch' && 'TestPyPI' || 'PyPI' }}
|
|
114
|
+
runs-on: ubuntu-latest
|
|
115
|
+
needs: [build]
|
|
116
|
+
environment: ${{ github.event_name == 'workflow_dispatch' && 'testpypi' || 'pypi' }}
|
|
117
|
+
permissions:
|
|
118
|
+
id-token: write # OIDC trusted publishing
|
|
119
|
+
attestations: write
|
|
120
|
+
contents: read
|
|
121
|
+
steps:
|
|
122
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
123
|
+
with:
|
|
124
|
+
name: dist
|
|
125
|
+
path: dist/
|
|
126
|
+
|
|
127
|
+
- name: Attest build provenance
|
|
128
|
+
# GitHub does not store attestations for user-owned *private* repos
|
|
129
|
+
# ("Feature not available for user-owned private repositories").
|
|
130
|
+
# Tolerate that on TestPyPI dry-runs so the publish path can still be
|
|
131
|
+
# rehearsed before the repo goes public; a real release (tag push)
|
|
132
|
+
# must ship provenance and therefore still fails loudly here.
|
|
133
|
+
continue-on-error: ${{ github.event_name == 'workflow_dispatch' }}
|
|
134
|
+
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
|
|
135
|
+
with:
|
|
136
|
+
subject-path: "dist/*"
|
|
137
|
+
|
|
138
|
+
- name: Publish
|
|
139
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
140
|
+
with:
|
|
141
|
+
repository-url: ${{ github.event_name == 'workflow_dispatch' && 'https://test.pypi.org/legacy/' || 'https://upload.pypi.org/legacy/' }}
|
|
142
|
+
# TestPyPI rejects re-uploads of the same version; tolerate them
|
|
143
|
+
# on dry-runs only so repeated dispatches don't fail. Real PyPI
|
|
144
|
+
# releases (tag push) must still fail loudly on a duplicate.
|
|
145
|
+
skip-existing: ${{ github.event_name == 'workflow_dispatch' }}
|
|
146
|
+
|
|
147
|
+
release:
|
|
148
|
+
name: GitHub Release
|
|
149
|
+
if: github.event_name == 'push'
|
|
150
|
+
runs-on: ubuntu-latest
|
|
151
|
+
needs: [publish]
|
|
152
|
+
permissions:
|
|
153
|
+
contents: write
|
|
154
|
+
steps:
|
|
155
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
156
|
+
|
|
157
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
158
|
+
with:
|
|
159
|
+
name: dist
|
|
160
|
+
path: dist/
|
|
161
|
+
|
|
162
|
+
- name: Create GitHub Release
|
|
163
|
+
env:
|
|
164
|
+
GH_TOKEN: ${{ github.token }}
|
|
165
|
+
run: gh release create "$GITHUB_REF_NAME" --generate-notes dist/*
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
*.egg
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
*.whl
|
|
11
|
+
.eggs/
|
|
12
|
+
|
|
13
|
+
# Virtual environments
|
|
14
|
+
.venv/
|
|
15
|
+
venv/
|
|
16
|
+
ENV/
|
|
17
|
+
|
|
18
|
+
# Testing
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.coverage
|
|
21
|
+
coverage.xml
|
|
22
|
+
coverage.lcov
|
|
23
|
+
htmlcov/
|
|
24
|
+
.mypy_cache/
|
|
25
|
+
|
|
26
|
+
# IDE
|
|
27
|
+
.idea/
|
|
28
|
+
*.swp
|
|
29
|
+
*.swo
|
|
30
|
+
*~
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# VSCode — keep shared settings, ignore user-specific files
|
|
35
|
+
.vscode/*
|
|
36
|
+
!.vscode/settings.json
|
|
37
|
+
!.vscode/extensions.json
|
|
38
|
+
!.vscode/launch.json
|
|
39
|
+
!.vscode/tasks.json
|
|
40
|
+
|
|
41
|
+
# Environment
|
|
42
|
+
.env
|
|
43
|
+
.env.local
|
|
44
|
+
|
|
45
|
+
# OS
|
|
46
|
+
.DS_Store
|
|
47
|
+
Thumbs.db
|
|
48
|
+
|
|
49
|
+
# Node.js (frontend)
|
|
50
|
+
|
|
51
|
+
# Alembic
|
|
52
|
+
*.db
|
|
53
|
+
|
|
54
|
+
# Docker
|
|
55
|
+
docker-compose.override.yaml
|
|
56
|
+
docker-compose.override.yml
|
|
57
|
+
|
|
58
|
+
# Local diagnostics
|
|
59
|
+
.diagnostics/
|
|
60
|
+
.vite/
|
|
61
|
+
|
|
62
|
+
# Project review reports
|
|
63
|
+
docs/report/
|
|
64
|
+
tmp/
|
|
65
|
+
|
|
66
|
+
# FPGA test fixture binaries (generated or downloaded — not committed)
|
|
67
|
+
tests/fixtures/binaries/
|
|
68
|
+
!tests/fixtures/binaries/.gitkeep
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.11
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Contributing to FabricGate (CLI/SDK)
|
|
2
|
+
|
|
3
|
+
Thanks for your interest. This repository holds the public client side of FabricGate: the CLI, the Python SDK, the shared models and the API contracts. Bug reports, board additions, documentation fixes and features are all welcome.
|
|
4
|
+
|
|
5
|
+
## Development setup
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
git clone https://github.com/harurun78/fabricgate.git
|
|
9
|
+
cd fabricgate
|
|
10
|
+
uv sync # https://docs.astral.sh/uv/ (installs the dev group too)
|
|
11
|
+
uv run fabricgate --help
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Python 3.11+ is required. `uv.lock` is committed; CI installs with `--frozen`, so run `uv lock` when you change dependencies.
|
|
15
|
+
|
|
16
|
+
## Checks that CI runs
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
uv run ruff check .
|
|
20
|
+
uv run ruff format --check .
|
|
21
|
+
uv run mypy src
|
|
22
|
+
uv run pytest -q
|
|
23
|
+
uv build
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
All of them must pass before a pull request is merged. Tests live in `tests/unit/`; fixtures in `tests/fixtures/`.
|
|
27
|
+
|
|
28
|
+
## Changing the API contracts
|
|
29
|
+
|
|
30
|
+
`docs/contracts/` is the source of truth for the registry's public API. The wire-format JSON Schemas are generated from the models:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
uv run python scripts/extract_schemas.py
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Commit the regenerated files together with the model change and add an entry to `docs/contracts/CHANGELOG.md`. Breaking changes to the *read* API are not accepted without a migration note; the write API is still marked MVP and may change.
|
|
37
|
+
|
|
38
|
+
## Adding a board to the Board DB
|
|
39
|
+
|
|
40
|
+
Boards live in `src/fabricgate/data/board-db/official.yaml` and are validated against `docs/contracts/schemas/board-db.schema.json` (`tests/unit/test_models.py`). Add an entry with `board_id`, `device`, the supported runtimes and a source URL for the identification data, and open a pull request. No code change is needed.
|
|
41
|
+
|
|
42
|
+
## Pull requests
|
|
43
|
+
|
|
44
|
+
- One purpose per pull request; keep unrelated refactors out.
|
|
45
|
+
- Conventional Commits for titles (`feat(cli): ...`, `fix(sdk): ...`, `docs: ...`).
|
|
46
|
+
- Describe how you verified the change. Screenshots are not needed; command output is.
|
|
47
|
+
- Do not add secrets, tokens or personal data to tests, fixtures or CI. The workflows in this repository run without any secrets by design.
|
|
48
|
+
- Please reference issues from **this** repository only. The registry implementation is developed elsewhere; if a change here depends on a server-side change, describe it in words rather than linking an internal issue number.
|
|
49
|
+
|
|
50
|
+
## Reporting bugs
|
|
51
|
+
|
|
52
|
+
Open an issue with the `fabricgate --version` output, the command you ran, and the full error text (`--verbose` helps). Security problems go to the address in [SECURITY.md](SECURITY.md), not to the issue tracker.
|
fabricgate-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FabricGate Contributors
|
|
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.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: fabricgate
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: FabricGate CLI/SDK — discover, pull and verify FPGA designs across boards and runtimes
|
|
5
|
+
Project-URL: Homepage, https://github.com/harurun78/fabricgate
|
|
6
|
+
Project-URL: Source, https://github.com/harurun78/fabricgate
|
|
7
|
+
Project-URL: Issues, https://github.com/harurun78/fabricgate/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/harurun78/fabricgate/blob/master/docs/contracts/CHANGELOG.md
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: bitstream,cli,fpga,pynq,registry
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Embedded Systems
|
|
21
|
+
Classifier: Topic :: System :: Hardware
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: click>=8.3.3
|
|
24
|
+
Requires-Dist: cryptography>=50.0.0
|
|
25
|
+
Requires-Dist: defusedxml>=0.7
|
|
26
|
+
Requires-Dist: email-validator>=2.2
|
|
27
|
+
Requires-Dist: httpx>=0.27
|
|
28
|
+
Requires-Dist: keyring>=25.0
|
|
29
|
+
Requires-Dist: pydantic-settings>=2.14.2
|
|
30
|
+
Requires-Dist: pydantic>=2.8
|
|
31
|
+
Requires-Dist: pyyaml>=6.0
|
|
32
|
+
Requires-Dist: rich>=13.7
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# FabricGate
|
|
36
|
+
|
|
37
|
+
[](https://github.com/harurun78/fabricgate/actions/workflows/ci.yaml)
|
|
38
|
+
[](LICENSE)
|
|
39
|
+
|
|
40
|
+
**Discover, pull and verify FPGA designs for your board — one command, any runtime.**
|
|
41
|
+
|
|
42
|
+
FabricGate is a package registry for FPGA designs (bitstreams plus the metadata a runtime needs to load them). This repository contains the client side: the `fabricgate` CLI, the Python SDK, the shared data models, and the public API contracts. The hosted registry lives at `https://registry.fabricgate.dev`.
|
|
43
|
+
|
|
44
|
+
> **Status: alpha.** The registry is being seeded with community PYNQ overlays. Interfaces marked *stable* in `docs/specs/` are kept backward compatible; everything else may still change before 1.0.
|
|
45
|
+
|
|
46
|
+
## Install
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
pip install fabricgate
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Python 3.11 or newer. `fgate` is installed as a short alias of `fabricgate`.
|
|
53
|
+
|
|
54
|
+
## Three steps to a running design
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
# 1. Find a design for your board
|
|
58
|
+
fabricgate search --platform pynq-z2/pynq adder
|
|
59
|
+
|
|
60
|
+
# 2. Pull it (bitstream + hwh + manifest, digests verified on download)
|
|
61
|
+
fabricgate pull example/adder-demo:1.0.0 --platform pynq-z2/pynq
|
|
62
|
+
|
|
63
|
+
# 3. Load it with the runtime you already use
|
|
64
|
+
python -c "from pynq import Overlay; ol = Overlay('adder-demo/adder.bit')"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`example/adder-demo` is a placeholder name; run `fabricgate search` to see what is actually published. The `--platform` value is `<board>/<runtime>`; run `fabricgate pull --help` for the resolution rules, including the `generic-<device>` fallback.
|
|
68
|
+
|
|
69
|
+
## What the CLI can do
|
|
70
|
+
|
|
71
|
+
| Command | Purpose |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `search`, `info`, `diff`, `stats`, `watch` | discover designs and track updates |
|
|
74
|
+
| `pull`, `verify`, `list` | download with digest verification, re-verify, inspect the local cache |
|
|
75
|
+
| `build`, `push`, `yank`, `deprecate` | publish your own designs (`build` generates the Platform Manifest and Design Index from a build directory) |
|
|
76
|
+
| `login`, `token`, `quota`, `webhook`, `license-check` | account, automation and policy helpers |
|
|
77
|
+
|
|
78
|
+
`fabricgate --json` gives machine-readable output for every command.
|
|
79
|
+
|
|
80
|
+
## Supported boards and runtimes
|
|
81
|
+
|
|
82
|
+
The bundled Board DB (`src/fabricgate/data/board-db/official.yaml`) currently knows these boards:
|
|
83
|
+
|
|
84
|
+
| Board | Device | Runtime |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| `pynq-z2` | xc7z020 | `pynq` |
|
|
87
|
+
| `zcu104` | xczu7ev | `pynq`, `linux-fpgamgr` |
|
|
88
|
+
| `pico-ice` | iCE40UP5K | `nanopynq` (Phase 3, forward reference) |
|
|
89
|
+
| `generic-xc7z020`, `generic-xczu7ev` | — | device-level fallback for boards not yet listed |
|
|
90
|
+
|
|
91
|
+
Adding a board is a data change; see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
92
|
+
|
|
93
|
+
## SDK
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from fabricgate.sdk import api
|
|
97
|
+
|
|
98
|
+
result = api.pull("example/adder-demo:1.0.0", platform="pynq-z2/pynq")
|
|
99
|
+
print(result.artifacts)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The SDK wraps the same client the CLI uses. See `docs/specs/client-behavior.md` for the resolution and caching rules.
|
|
103
|
+
|
|
104
|
+
## Public contracts
|
|
105
|
+
|
|
106
|
+
`docs/contracts/` is the source of truth for the registry's public API:
|
|
107
|
+
|
|
108
|
+
- `openapi.yaml` / `openapi.json` — Registry HTTP API
|
|
109
|
+
- `schemas/design-index.schema.json`, `schemas/platform-manifest.schema.json`, `schemas/board-db.schema.json` — wire formats
|
|
110
|
+
- `CHANGELOG.md` — contract changes and migration notes
|
|
111
|
+
|
|
112
|
+
Specifications for the CLI, client behaviour and data formats are in `docs/specs/`.
|
|
113
|
+
|
|
114
|
+
## Self-hosting and the registry implementation
|
|
115
|
+
|
|
116
|
+
The registry server is operated as a hosted service and its implementation is not published at this stage (see `docs/specs/` for the distribution policy summary in `client-behavior.md`). Everything a client needs to interoperate — API, schemas, error formats — is in this repository, so alternative implementations are possible.
|
|
117
|
+
|
|
118
|
+
## Contributing, security, license
|
|
119
|
+
|
|
120
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md) — development setup, tests, pull requests
|
|
121
|
+
- [SECURITY.md](SECURITY.md) — how to report a vulnerability
|
|
122
|
+
- [LICENSE](LICENSE) — MIT
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# FabricGate
|
|
2
|
+
|
|
3
|
+
[](https://github.com/harurun78/fabricgate/actions/workflows/ci.yaml)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
**Discover, pull and verify FPGA designs for your board — one command, any runtime.**
|
|
7
|
+
|
|
8
|
+
FabricGate is a package registry for FPGA designs (bitstreams plus the metadata a runtime needs to load them). This repository contains the client side: the `fabricgate` CLI, the Python SDK, the shared data models, and the public API contracts. The hosted registry lives at `https://registry.fabricgate.dev`.
|
|
9
|
+
|
|
10
|
+
> **Status: alpha.** The registry is being seeded with community PYNQ overlays. Interfaces marked *stable* in `docs/specs/` are kept backward compatible; everything else may still change before 1.0.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
pip install fabricgate
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Python 3.11 or newer. `fgate` is installed as a short alias of `fabricgate`.
|
|
19
|
+
|
|
20
|
+
## Three steps to a running design
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
# 1. Find a design for your board
|
|
24
|
+
fabricgate search --platform pynq-z2/pynq adder
|
|
25
|
+
|
|
26
|
+
# 2. Pull it (bitstream + hwh + manifest, digests verified on download)
|
|
27
|
+
fabricgate pull example/adder-demo:1.0.0 --platform pynq-z2/pynq
|
|
28
|
+
|
|
29
|
+
# 3. Load it with the runtime you already use
|
|
30
|
+
python -c "from pynq import Overlay; ol = Overlay('adder-demo/adder.bit')"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`example/adder-demo` is a placeholder name; run `fabricgate search` to see what is actually published. The `--platform` value is `<board>/<runtime>`; run `fabricgate pull --help` for the resolution rules, including the `generic-<device>` fallback.
|
|
34
|
+
|
|
35
|
+
## What the CLI can do
|
|
36
|
+
|
|
37
|
+
| Command | Purpose |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `search`, `info`, `diff`, `stats`, `watch` | discover designs and track updates |
|
|
40
|
+
| `pull`, `verify`, `list` | download with digest verification, re-verify, inspect the local cache |
|
|
41
|
+
| `build`, `push`, `yank`, `deprecate` | publish your own designs (`build` generates the Platform Manifest and Design Index from a build directory) |
|
|
42
|
+
| `login`, `token`, `quota`, `webhook`, `license-check` | account, automation and policy helpers |
|
|
43
|
+
|
|
44
|
+
`fabricgate --json` gives machine-readable output for every command.
|
|
45
|
+
|
|
46
|
+
## Supported boards and runtimes
|
|
47
|
+
|
|
48
|
+
The bundled Board DB (`src/fabricgate/data/board-db/official.yaml`) currently knows these boards:
|
|
49
|
+
|
|
50
|
+
| Board | Device | Runtime |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| `pynq-z2` | xc7z020 | `pynq` |
|
|
53
|
+
| `zcu104` | xczu7ev | `pynq`, `linux-fpgamgr` |
|
|
54
|
+
| `pico-ice` | iCE40UP5K | `nanopynq` (Phase 3, forward reference) |
|
|
55
|
+
| `generic-xc7z020`, `generic-xczu7ev` | — | device-level fallback for boards not yet listed |
|
|
56
|
+
|
|
57
|
+
Adding a board is a data change; see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
58
|
+
|
|
59
|
+
## SDK
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from fabricgate.sdk import api
|
|
63
|
+
|
|
64
|
+
result = api.pull("example/adder-demo:1.0.0", platform="pynq-z2/pynq")
|
|
65
|
+
print(result.artifacts)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The SDK wraps the same client the CLI uses. See `docs/specs/client-behavior.md` for the resolution and caching rules.
|
|
69
|
+
|
|
70
|
+
## Public contracts
|
|
71
|
+
|
|
72
|
+
`docs/contracts/` is the source of truth for the registry's public API:
|
|
73
|
+
|
|
74
|
+
- `openapi.yaml` / `openapi.json` — Registry HTTP API
|
|
75
|
+
- `schemas/design-index.schema.json`, `schemas/platform-manifest.schema.json`, `schemas/board-db.schema.json` — wire formats
|
|
76
|
+
- `CHANGELOG.md` — contract changes and migration notes
|
|
77
|
+
|
|
78
|
+
Specifications for the CLI, client behaviour and data formats are in `docs/specs/`.
|
|
79
|
+
|
|
80
|
+
## Self-hosting and the registry implementation
|
|
81
|
+
|
|
82
|
+
The registry server is operated as a hosted service and its implementation is not published at this stage (see `docs/specs/` for the distribution policy summary in `client-behavior.md`). Everything a client needs to interoperate — API, schemas, error formats — is in this repository, so alternative implementations are possible.
|
|
83
|
+
|
|
84
|
+
## Contributing, security, license
|
|
85
|
+
|
|
86
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md) — development setup, tests, pull requests
|
|
87
|
+
- [SECURITY.md](SECURITY.md) — how to report a vulnerability
|
|
88
|
+
- [LICENSE](LICENSE) — MIT
|