Skip to content

Commit 36fb44e

Browse files
committed
feat(sdk): initial standalone SDK repo
Extracted from ITL.ControlPlane.Attestation monorepo (src/sdk/). - src/sdk/ layout with hatchling build backend - Standalone CI workflow (lint, test, build, auto-tag, release) - PyPI publish workflow with OIDC Trusted Publisher - Updated project URLs to this repo
0 parents  commit 36fb44e

23 files changed

Lines changed: 2282 additions & 0 deletions

.github/workflows/ci.yml

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
name: CI
2+
3+
# ---------------------------------------------------------------------------
4+
# CI for itl-attestation-sdk
5+
# detect-version → lint + test + build wheel → auto-tag → GitHub Release
6+
# ---------------------------------------------------------------------------
7+
on:
8+
push:
9+
branches: [main, develop, "feature/**", "release/**", "hotfix/**"]
10+
pull_request:
11+
branches: [main, develop]
12+
workflow_dispatch:
13+
14+
concurrency:
15+
group: ci-${{ github.ref }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
20+
detect-version:
21+
name: Detect version
22+
uses: ITlusions/ITL.Github/.github/workflows/_reusable-detect-version.yml@main
23+
with:
24+
tag-prefix: "v"
25+
26+
ci:
27+
name: Lint / Test / Build
28+
needs: detect-version
29+
uses: ITlusions/ITL.Github/.github/workflows/_reusable-ci-python.yml@main
30+
with:
31+
python-version: "3.12"
32+
ref: ${{ github.sha }}
33+
artifact-name: "sdk-wheel"
34+
version: ${{ needs.detect-version.outputs.python-version }}
35+
ruff-src: "."
36+
test-path: "tests/"
37+
extra-install: "pip install -e .[dev]"
38+
39+
build-meta:
40+
name: Compute build ID
41+
runs-on: ubuntu-latest
42+
outputs:
43+
build-id: ${{ steps.id.outputs.build-id }}
44+
steps:
45+
- name: Generate build ID
46+
id: id
47+
run: echo "build-id=$(date +%Y%m%d)-${{ github.run_number }}" >> "$GITHUB_OUTPUT"
48+
49+
auto-tag:
50+
name: Auto-tag semver
51+
needs: ci
52+
if: |
53+
github.event_name == 'push' &&
54+
(
55+
github.ref == 'refs/heads/main' ||
56+
startsWith(github.ref, 'refs/heads/release/')
57+
)
58+
uses: ITlusions/ITL.Github/.github/workflows/_reusable-auto-tag.yml@main
59+
with:
60+
commit-sha: ${{ github.sha }}
61+
tag-prefix: "v"
62+
secrets:
63+
gh-pat: ${{ secrets.GH_PAT }}
64+
65+
create-release:
66+
name: Create GitHub Release
67+
needs: [auto-tag, build-meta]
68+
if: |
69+
github.event_name == 'push' &&
70+
(
71+
github.ref == 'refs/heads/main' ||
72+
startsWith(github.ref, 'refs/heads/release/')
73+
)
74+
uses: ITlusions/ITL.Github/.github/workflows/_reusable-release-gh.yml@main
75+
with:
76+
tag: ${{ needs.auto-tag.outputs.tag }}
77+
artifact-name: "sdk-wheel"
78+
artifact-run-id: ${{ github.run_id }}
79+
generate-release-notes: true
80+
body: |
81+
## Installation
82+
83+
**From PyPI**
84+
```bash
85+
pip install itl-attestation-sdk==${{ needs.detect-version.outputs.python-version }}
86+
```
87+
88+
**From GitHub (this release)**
89+
```bash
90+
pip install "itl-attestation-sdk @ https://github.com/${{ github.repository }}/releases/download/${{ needs.auto-tag.outputs.tag }}/$(ls dist/*.whl | xargs basename)"
91+
```
92+
93+
**From source**
94+
```bash
95+
git clone https://github.com/${{ github.repository }}.git
96+
cd ITL.ControlPlane.Attestation.Sdk
97+
pip install .
98+
```
99+
100+
---
101+
**Build:** ${{ needs.build-meta.outputs.build-id }}
102+
**Commit:** ${{ github.sha }}
103+
**Workflow run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
104+
secrets:
105+
gh-pat: ${{ secrets.GH_PAT }}

.github/workflows/publish.yml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: Publish — Release published
2+
3+
# ---------------------------------------------------------------------------
4+
# Publish orchestrator for itl-attestation-sdk
5+
#
6+
# Triggered when a GitHub Release is published (from create-release in ci.yml).
7+
# Releases are created using GH_PAT so the release:published event fires.
8+
#
9+
# Authentication: PyPI Trusted Publisher (OIDC) — no API tokens.
10+
# ---------------------------------------------------------------------------
11+
on:
12+
release:
13+
types: [published]
14+
15+
concurrency:
16+
group: publish-${{ github.event.release.tag_name }}
17+
cancel-in-progress: false
18+
19+
jobs:
20+
21+
resolve-version:
22+
name: Resolve release version
23+
runs-on: ubuntu-latest
24+
outputs:
25+
version: ${{ steps.ver.outputs.version }}
26+
prerelease: ${{ steps.ver.outputs.prerelease }}
27+
steps:
28+
- name: Extract version from tag
29+
id: ver
30+
run: |
31+
TAG="${{ github.event.release.tag_name }}"
32+
VERSION="${TAG#v}"
33+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
34+
if [[ "$VERSION" == *"-"* ]]; then
35+
echo "prerelease=true" >> "$GITHUB_OUTPUT"
36+
else
37+
echo "prerelease=false" >> "$GITHUB_OUTPUT"
38+
fi
39+
40+
publish-pypi:
41+
name: Publish to PyPI
42+
needs: resolve-version
43+
if: needs.resolve-version.outputs.prerelease == 'false'
44+
runs-on: ubuntu-latest
45+
environment: pypi
46+
permissions:
47+
id-token: write # OIDC Trusted Publisher
48+
steps:
49+
- name: Download wheel artifact
50+
uses: dawidd6/action-download-artifact@v6
51+
with:
52+
github_token: ${{ secrets.GH_PAT }}
53+
workflow: ci.yml
54+
commit: ${{ github.sha }}
55+
name: sdk-wheel
56+
path: dist/
57+
58+
- name: Publish to PyPI
59+
uses: pypa/gh-action-pypi-publish@release/v1
60+
61+
publish-testpypi:
62+
name: Publish to TestPyPI (pre-release)
63+
needs: resolve-version
64+
if: needs.resolve-version.outputs.prerelease == 'true'
65+
runs-on: ubuntu-latest
66+
environment: testpypi
67+
permissions:
68+
id-token: write # OIDC Trusted Publisher
69+
steps:
70+
- name: Download wheel artifact
71+
uses: dawidd6/action-download-artifact@v6
72+
with:
73+
github_token: ${{ secrets.GH_PAT }}
74+
workflow: ci.yml
75+
commit: ${{ github.sha }}
76+
name: sdk-wheel
77+
path: dist/
78+
79+
- name: Publish to TestPyPI
80+
uses: pypa/gh-action-pypi-publish@release/v1
81+
with:
82+
repository-url: https://test.pypi.org/legacy/

.gitignore

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
*.so
6+
7+
# Distribution / packaging
8+
.Python
9+
build/
10+
develop-eggs/
11+
dist/
12+
downloads/
13+
eggs/
14+
.eggs/
15+
lib/
16+
lib64/
17+
parts/
18+
sdist/
19+
var/
20+
wheels/
21+
share/python-wheels/
22+
*.egg-info/
23+
.installed.cfg
24+
*.egg
25+
MANIFEST
26+
27+
# PyInstaller
28+
*.manifest
29+
*.spec
30+
31+
# Unit test / coverage reports
32+
htmlcov/
33+
.tox/
34+
.nox/
35+
.coverage
36+
.coverage.*
37+
.cache
38+
nosetests.xml
39+
coverage.xml
40+
*.cover
41+
*.py,cover
42+
.hypothesis/
43+
.pytest_cache/
44+
cover/
45+
46+
# mypy
47+
.mypy_cache/
48+
.dmypy.json
49+
dmypy.json
50+
51+
# Pyre type checker
52+
.pyre/
53+
54+
# pytype static type analyzer
55+
.pytype/
56+
57+
# Ruff
58+
.ruff_cache/
59+
60+
# Environments
61+
.env
62+
.venv
63+
env/
64+
venv/
65+
ENV/
66+
env.bak/
67+
venv.bak/
68+
69+
# IDEs
70+
.vscode/
71+
.idea/
72+
*.swp
73+
*.swo
74+
*~
75+
76+
# OS
77+
.DS_Store
78+
Thumbs.db
79+
80+
# Database files (for testing)
81+
*.db
82+
*.db-journal
83+
*.db-wal
84+
*.db-shm

CHANGELOG.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Changelog
2+
3+
All notable changes to the ITL Attestation SDK will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [0.1.0] - 2026-05-15
9+
10+
### Added
11+
- Initial SDK release with core infrastructure
12+
- `core/config.py` — AttestationConfig with Pydantic BaseSettings
13+
- `core/database.py` — Async SQLAlchemy engine and session factory
14+
- `core/exceptions.py` — Complete exception hierarchy
15+
- `models/machine.py` — MachineRow, NodeRole, MachineStatus ORM models
16+
- `models/operator.py` — AuditLogRow with cryptographic chain, ApprovalRequestRow
17+
- `repositories/machine_repo.py` — SqlMachineRepository with full CRUD
18+
- `repositories/operator_repo.py` — AuditRepository with hash verification, ApprovalRequestRepository
19+
- Comprehensive README with usage examples
20+
- Full type hints and mypy strict mode support
21+
- Environment-based configuration
22+
- Support for SQLite and async database operations
23+
24+
### Features
25+
- **Cryptographic audit chain** — Hash-based integrity verification for audit logs
26+
- **TPM attestation models** — EK fingerprint, AK public key, hardware UUID tracking
27+
- **Dual-control approval workflow** — Multi-operator approval requests
28+
- **Machine lifecycle states** — pending_approval → registered → attested → locked/revoked
29+
- **Node role support** — Control plane, worker infrastructure, worker application tiers
30+
- **Source IP tracking** — All audit log entries include originating IP address
31+
32+
### Dependencies
33+
- SQLModel >=0.0.16
34+
- SQLAlchemy[asyncio] >=2.0.0
35+
- aiosqlite >=0.19.0
36+
- Pydantic >=2.0.0
37+
- Pydantic-settings >=2.0.0
38+
39+
[0.1.0]: https://github.com/ITLusions/ITL.ControlPlane.Attestation/releases/tag/v0.1.0

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 ITLusions
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 commit comments

Comments
 (0)