infralink-ops 0.2.67__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 (104) hide show
  1. infralink_ops-0.2.67/.github/workflows/publish-pypi.yml +91 -0
  2. infralink_ops-0.2.67/.gitignore +5 -0
  3. infralink_ops-0.2.67/.woodpecker.yml +56 -0
  4. infralink_ops-0.2.67/Dockerfile +18 -0
  5. infralink_ops-0.2.67/Dockerfile.controller +60 -0
  6. infralink_ops-0.2.67/Dockerfile.ops +11 -0
  7. infralink_ops-0.2.67/PKG-INFO +158 -0
  8. infralink_ops-0.2.67/README.md +143 -0
  9. infralink_ops-0.2.67/docs/controller-runtime-guide.md +72 -0
  10. infralink_ops-0.2.67/docs/superpowers/plans/2026-08-22-static-config-trees.md +255 -0
  11. infralink_ops-0.2.67/docs/superpowers/plans/2026-08-23-public-firewall-runtime.md +48 -0
  12. infralink_ops-0.2.67/docs/superpowers/plans/2026-08-25-declared-template-sources.md +30 -0
  13. infralink_ops-0.2.67/docs/superpowers/plans/2026-08-26-independent-artifact-renderer-source.md +49 -0
  14. infralink_ops-0.2.67/docs/superpowers/specs/2026-08-26-independent-artifact-renderer-source-design.md +17 -0
  15. infralink_ops-0.2.67/gitea-hooks/entrypoint +5 -0
  16. infralink_ops-0.2.67/gitea-hooks/install-receive-gate +11 -0
  17. infralink_ops-0.2.67/gitea-hooks/pre-receive-gitleaks +25 -0
  18. infralink_ops-0.2.67/pyproject.toml +58 -0
  19. infralink_ops-0.2.67/src/infralink_ops/__init__.py +60 -0
  20. infralink_ops-0.2.67/src/infralink_ops/artifact_installer.py +127 -0
  21. infralink_ops-0.2.67/src/infralink_ops/artifact_renderer_source.py +94 -0
  22. infralink_ops-0.2.67/src/infralink_ops/artifact_target_install.py +187 -0
  23. infralink_ops-0.2.67/src/infralink_ops/assets/infralink +73 -0
  24. infralink_ops-0.2.67/src/infralink_ops/assets/infralink-host +112 -0
  25. infralink_ops-0.2.67/src/infralink_ops/assets/infralink-host-reconcile.service +8 -0
  26. infralink_ops-0.2.67/src/infralink_ops/assets/infralink-host-reconcile.timer +11 -0
  27. infralink_ops-0.2.67/src/infralink_ops/bounded_process.py +409 -0
  28. infralink_ops-0.2.67/src/infralink_ops/canonical_json.py +57 -0
  29. infralink_ops-0.2.67/src/infralink_ops/cli.py +34 -0
  30. infralink_ops-0.2.67/src/infralink_ops/compose_binds.py +67 -0
  31. infralink_ops-0.2.67/src/infralink_ops/compose_state_protocol.py +656 -0
  32. infralink_ops-0.2.67/src/infralink_ops/config_trees.py +478 -0
  33. infralink_ops-0.2.67/src/infralink_ops/controller_adapter.py +86 -0
  34. infralink_ops-0.2.67/src/infralink_ops/controller_adapter_runnable.py +85 -0
  35. infralink_ops-0.2.67/src/infralink_ops/controller_artifacts.py +220 -0
  36. infralink_ops-0.2.67/src/infralink_ops/controller_bootstrap.py +406 -0
  37. infralink_ops-0.2.67/src/infralink_ops/controller_config_consumers.py +328 -0
  38. infralink_ops-0.2.67/src/infralink_ops/controller_doctor.py +333 -0
  39. infralink_ops-0.2.67/src/infralink_ops/controller_firewall.py +136 -0
  40. infralink_ops-0.2.67/src/infralink_ops/controller_host_interface.py +234 -0
  41. infralink_ops-0.2.67/src/infralink_ops/controller_images.py +184 -0
  42. infralink_ops-0.2.67/src/infralink_ops/controller_metrics.py +161 -0
  43. infralink_ops-0.2.67/src/infralink_ops/controller_protected_transitions.py +244 -0
  44. infralink_ops-0.2.67/src/infralink_ops/controller_reconcile_evidence.py +223 -0
  45. infralink_ops-0.2.67/src/infralink_ops/controller_registry_checkout.py +103 -0
  46. infralink_ops-0.2.67/src/infralink_ops/controller_render_secrets.py +174 -0
  47. infralink_ops-0.2.67/src/infralink_ops/controller_runtime_directories.py +210 -0
  48. infralink_ops-0.2.67/src/infralink_ops/dashboards.py +186 -0
  49. infralink_ops-0.2.67/src/infralink_ops/declared_file_destination.py +61 -0
  50. infralink_ops-0.2.67/src/infralink_ops/egress_snat.py +241 -0
  51. infralink_ops-0.2.67/src/infralink_ops/firewall.py +293 -0
  52. infralink_ops-0.2.67/src/infralink_ops/host_interface_assets.py +23 -0
  53. infralink_ops-0.2.67/src/infralink_ops/image_resolution.py +253 -0
  54. infralink_ops-0.2.67/src/infralink_ops/observation.py +47 -0
  55. infralink_ops-0.2.67/src/infralink_ops/registry_checkout.py +146 -0
  56. infralink_ops-0.2.67/src/infralink_ops/registry_transport_trust.py +96 -0
  57. infralink_ops-0.2.67/src/infralink_ops/stable_regular_file.py +66 -0
  58. infralink_ops-0.2.67/src/infralink_ops/template_dependencies.py +133 -0
  59. infralink_ops-0.2.67/src/infralink_ops/template_renderer.py +492 -0
  60. infralink_ops-0.2.67/src/infralink_ops/template_source_dependencies.py +148 -0
  61. infralink_ops-0.2.67/src/infralink_ops/template_sources.py +99 -0
  62. infralink_ops-0.2.67/src/infralink_ops/typed_artifact_materializer.py +294 -0
  63. infralink_ops-0.2.67/tests/receive-gate.sh +44 -0
  64. infralink_ops-0.2.67/tests/runtime-image.sh +46 -0
  65. infralink_ops-0.2.67/tests/test_artifact_installer.py +71 -0
  66. infralink_ops-0.2.67/tests/test_artifact_renderer_source.py +90 -0
  67. infralink_ops-0.2.67/tests/test_artifact_target_install.py +137 -0
  68. infralink_ops-0.2.67/tests/test_bounded_process.py +693 -0
  69. infralink_ops-0.2.67/tests/test_canonical_json.py +29 -0
  70. infralink_ops-0.2.67/tests/test_compose_binds.py +88 -0
  71. infralink_ops-0.2.67/tests/test_compose_state_protocol.py +243 -0
  72. infralink_ops-0.2.67/tests/test_config_trees.py +476 -0
  73. infralink_ops-0.2.67/tests/test_controller_adapter_runnable.py +209 -0
  74. infralink_ops-0.2.67/tests/test_controller_adapter_transport.py +176 -0
  75. infralink_ops-0.2.67/tests/test_controller_artifacts.py +271 -0
  76. infralink_ops-0.2.67/tests/test_controller_bootstrap.py +313 -0
  77. infralink_ops-0.2.67/tests/test_controller_config_consumers.py +381 -0
  78. infralink_ops-0.2.67/tests/test_controller_doctor.py +413 -0
  79. infralink_ops-0.2.67/tests/test_controller_firewall.py +161 -0
  80. infralink_ops-0.2.67/tests/test_controller_host_interface.py +135 -0
  81. infralink_ops-0.2.67/tests/test_controller_image_recipe.py +25 -0
  82. infralink_ops-0.2.67/tests/test_controller_images.py +199 -0
  83. infralink_ops-0.2.67/tests/test_controller_metrics.py +164 -0
  84. infralink_ops-0.2.67/tests/test_controller_protected_transitions.py +78 -0
  85. infralink_ops-0.2.67/tests/test_controller_reconcile_evidence.py +267 -0
  86. infralink_ops-0.2.67/tests/test_controller_registry_checkout.py +110 -0
  87. infralink_ops-0.2.67/tests/test_controller_render_secrets.py +94 -0
  88. infralink_ops-0.2.67/tests/test_controller_runtime_directories.py +193 -0
  89. infralink_ops-0.2.67/tests/test_dashboard_catalog.py +161 -0
  90. infralink_ops-0.2.67/tests/test_declared_file_destination.py +43 -0
  91. infralink_ops-0.2.67/tests/test_direct_projection.py +85 -0
  92. infralink_ops-0.2.67/tests/test_docs_contract.py +134 -0
  93. infralink_ops-0.2.67/tests/test_egress_snat.py +397 -0
  94. infralink_ops-0.2.67/tests/test_firewall.py +224 -0
  95. infralink_ops-0.2.67/tests/test_github_pypi_publish_policy.py +84 -0
  96. infralink_ops-0.2.67/tests/test_host_interface_assets.py +67 -0
  97. infralink_ops-0.2.67/tests/test_image_resolution.py +140 -0
  98. infralink_ops-0.2.67/tests/test_registry_checkout.py +217 -0
  99. infralink_ops-0.2.67/tests/test_registry_transport_trust.py +46 -0
  100. infralink_ops-0.2.67/tests/test_stable_regular_file.py +66 -0
  101. infralink_ops-0.2.67/tests/test_template_dependencies.py +153 -0
  102. infralink_ops-0.2.67/tests/test_template_renderer.py +473 -0
  103. infralink_ops-0.2.67/tests/test_template_source_dependencies.py +124 -0
  104. infralink_ops-0.2.67/tests/test_typed_artifact_materializer.py +389 -0
@@ -0,0 +1,91 @@
1
+ name: Publish Python package
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ tag:
7
+ description: Existing Infralink Ops release tag to publish to TestPyPI
8
+ required: true
9
+ type: string
10
+ release:
11
+ types: [published]
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ build:
18
+ name: Build distributions
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - name: Check out repository
22
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
+ with:
24
+ persist-credentials: false
25
+ ref: refs/tags/${{ github.event.release.tag_name || inputs.tag }}
26
+ - name: Set up Python
27
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
28
+ with:
29
+ python-version: "3.12"
30
+ - name: Install release dependencies
31
+ env:
32
+ PIP_EXTRA_INDEX_URL: ${{ github.event_name == 'workflow_dispatch' && 'https://test.pypi.org/simple' || '' }}
33
+ run: python -m pip install --disable-pip-version-check "twine>=6.0" -e ".[dev]"
34
+ - name: Verify release tag
35
+ env:
36
+ RELEASE_TAG: ${{ github.event.release.tag_name || inputs.tag }}
37
+ run: >-
38
+ python -c "import os, tomllib;
39
+ version = tomllib.load(open('pyproject.toml', 'rb'))['project']['version'];
40
+ actual = os.environ['RELEASE_TAG']; expected = f'v{version}';
41
+ assert actual == expected, f'release tag {actual!r} must equal {expected!r}'"
42
+ - name: Build distributions
43
+ run: python -m build
44
+ - name: Validate distribution metadata
45
+ run: python -m twine check dist/*
46
+ - name: Store distributions
47
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
48
+ with:
49
+ name: python-package-distributions
50
+ path: dist/
51
+ if-no-files-found: error
52
+
53
+ publish-testpypi:
54
+ name: Publish to TestPyPI
55
+ if: github.event_name == 'workflow_dispatch'
56
+ needs: build
57
+ runs-on: ubuntu-latest
58
+ environment:
59
+ name: testpypi
60
+ url: https://test.pypi.org/p/infralink-ops
61
+ permissions:
62
+ id-token: write
63
+ steps:
64
+ - name: Retrieve distributions
65
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
66
+ with:
67
+ name: python-package-distributions
68
+ path: dist/
69
+ - name: Publish distributions
70
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
71
+ with:
72
+ repository-url: https://test.pypi.org/legacy/
73
+
74
+ publish-pypi:
75
+ name: Publish to PyPI
76
+ if: github.event_name == 'release'
77
+ needs: build
78
+ runs-on: ubuntu-latest
79
+ environment:
80
+ name: pypi
81
+ url: https://pypi.org/p/infralink-ops
82
+ permissions:
83
+ id-token: write
84
+ steps:
85
+ - name: Retrieve distributions
86
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
87
+ with:
88
+ name: python-package-distributions
89
+ path: dist/
90
+ - name: Publish distributions
91
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
@@ -0,0 +1,5 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ dist/
4
+ *.egg-info/
5
+ .venv/
@@ -0,0 +1,56 @@
1
+ steps:
2
+ docs-contract:
3
+ image: python:3.12-slim-bookworm
4
+ commands:
5
+ - python -m pip install --disable-pip-version-check pytest
6
+ - python -m pytest -q tests/test_docs_contract.py
7
+
8
+ test-python:
9
+ image: python:3.12-slim-bookworm
10
+ commands:
11
+ - sed -i 's|http://deb.debian.org|https://deb.debian.org|g' /etc/apt/sources.list.d/debian.sources
12
+ - apt-get update && apt-get install --yes --no-install-recommends git && rm -rf /var/lib/apt/lists/*
13
+ # Infralink is distributed from GitHub rather than a package index. Keep this
14
+ # CI fixture deterministic while the package declaration admits 0.6.x.
15
+ - python -m pip install --disable-pip-version-check 'infralink @ https://github.com/cyberstorm-dev/infralink/releases/download/v0.6.14/infralink-0.6.14-py3-none-any.whl#sha256=e41e16e082df50d7506785feb40dc3ea48087d46c391e31f2bd77e3ef81ce0e3'
16
+ - python -m pip install --disable-pip-version-check -e '.[dev]'
17
+ - python -m ruff check src tests
18
+ - python -m ruff format --check src tests
19
+ - python -m pytest -q
20
+ - python -m build
21
+ - python -m venv /tmp/infralink-ops-wheel
22
+ - /tmp/infralink-ops-wheel/bin/pip install --disable-pip-version-check 'infralink @ https://github.com/cyberstorm-dev/infralink/releases/download/v0.6.14/infralink-0.6.14-py3-none-any.whl#sha256=e41e16e082df50d7506785feb40dc3ea48087d46c391e31f2bd77e3ef81ce0e3'
23
+ - /tmp/infralink-ops-wheel/bin/pip install --disable-pip-version-check dist/*.whl
24
+ - cd /tmp && /tmp/infralink-ops-wheel/bin/python -c 'import infralink_ops'
25
+
26
+ build-infralink-ops-controller:
27
+ image: woodpeckerci/plugin-docker-buildx
28
+ settings:
29
+ registry: ghcr.io
30
+ repo: ghcr.io/cyberstorm-dev/infralink-ops-controller
31
+ dockerfile: Dockerfile.controller
32
+ context: .
33
+ dry_run: true
34
+ tags:
35
+ - local-test-${CI_COMMIT_SHA:0:7}
36
+
37
+ publish-infralink-ops-controller:
38
+ image: woodpeckerci/plugin-docker-buildx
39
+ depends_on:
40
+ - build-infralink-ops-controller
41
+ when:
42
+ - event: push
43
+ branch: main
44
+ settings:
45
+ registry: ghcr.io
46
+ repo: ghcr.io/cyberstorm-dev/infralink-ops-controller
47
+ dockerfile: Dockerfile.controller
48
+ context: .
49
+ tags:
50
+ - head
51
+ - main
52
+ - sha-${CI_COMMIT_SHA:0:7}
53
+ username:
54
+ from_secret: ghcr_username
55
+ password:
56
+ from_secret: ghcr_token
@@ -0,0 +1,18 @@
1
+ ARG GITEA_IMAGE=gitea/gitea:1.27.2
2
+ ARG GITLEAKS_IMAGE=zricethezav/gitleaks:v8.30.0
3
+
4
+ FROM ${GITLEAKS_IMAGE} AS gitleaks
5
+
6
+ FROM ${GITEA_IMAGE}
7
+
8
+ USER root
9
+ COPY --from=gitleaks /usr/bin/gitleaks /usr/local/bin/gitleaks
10
+ COPY gitea-hooks/pre-receive-gitleaks /usr/local/lib/infralink-gitea-hooks/pre-receive-gitleaks
11
+ COPY gitea-hooks/install-receive-gate /usr/local/lib/infralink-gitea-hooks/install-receive-gate
12
+ COPY gitea-hooks/entrypoint /usr/local/bin/infralink-gitea-entrypoint
13
+ RUN chmod 0755 /usr/local/lib/infralink-gitea-hooks/* \
14
+ /usr/local/bin/infralink-gitea-entrypoint \
15
+ && mkdir -p /usr/local/share/infralink-gitea/git-template/hooks/pre-receive.d \
16
+ && cp /usr/local/lib/infralink-gitea-hooks/pre-receive-gitleaks /usr/local/share/infralink-gitea/git-template/hooks/pre-receive.d/20-infralink-gitleaks \
17
+ && git config --system init.templateDir /usr/local/share/infralink-gitea/git-template
18
+ ENTRYPOINT ["/usr/local/bin/infralink-gitea-entrypoint"]
@@ -0,0 +1,60 @@
1
+ FROM python@sha256:57cd7c3a7a273101a6485ba99423ee568157882804b1124b4dd04266317710de
2
+
3
+ ARG BWS_VERSION=1.0.0
4
+
5
+ ENV DEBIAN_FRONTEND=noninteractive \
6
+ PYTHONDONTWRITEBYTECODE=1 \
7
+ PYTHONUNBUFFERED=1
8
+
9
+ RUN sed -i 's|http://deb.debian.org|https://deb.debian.org|g' /etc/apt/sources.list.d/debian.sources \
10
+ && apt-get update -qq \
11
+ && apt-get install -y -qq --no-install-recommends \
12
+ ca-certificates \
13
+ curl \
14
+ git \
15
+ gnupg \
16
+ iptables \
17
+ jq \
18
+ lsb-release \
19
+ nftables \
20
+ openssh-client \
21
+ unzip \
22
+ util-linux \
23
+ yq \
24
+ && install -m 0755 -d /etc/apt/keyrings \
25
+ && curl -fsSL https://download.docker.com/linux/debian/gpg \
26
+ | gpg --dearmor -o /etc/apt/keyrings/docker.gpg \
27
+ && chmod a+r /etc/apt/keyrings/docker.gpg \
28
+ && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo \"$VERSION_CODENAME\") stable" \
29
+ > /etc/apt/sources.list.d/docker.list \
30
+ && apt-get update -qq \
31
+ && apt-get install -y -qq --no-install-recommends docker-ce-cli docker-compose-plugin \
32
+ && rm -rf /var/lib/apt/lists/*
33
+
34
+ RUN curl -fsSL "https://github.com/bitwarden/sdk/releases/download/bws-v${BWS_VERSION}/bws-x86_64-unknown-linux-gnu-${BWS_VERSION}.zip" \
35
+ -o /tmp/bws.zip \
36
+ && unzip -q /tmp/bws.zip -d /tmp \
37
+ && install -m 0755 /tmp/bws /usr/local/bin/bws \
38
+ && rm -f /tmp/bws.zip /tmp/bws
39
+
40
+ WORKDIR /app
41
+
42
+ COPY pyproject.toml README.md ./
43
+ COPY src ./src
44
+ # Infralink is not published to a package index; pin the controller build input
45
+ # while pyproject.toml expresses the supported 0.6.x compatibility range.
46
+ RUN python -m pip install --disable-pip-version-check --no-cache-dir \
47
+ 'infralink @ https://github.com/cyberstorm-dev/infralink/releases/download/v0.6.14/infralink-0.6.14-py3-none-any.whl#sha256=e41e16e082df50d7506785feb40dc3ea48087d46c391e31f2bd77e3ef81ce0e3' \
48
+ && python -m pip install --disable-pip-version-check --no-cache-dir . \
49
+ && command -v infralink-controller-registry-checkout \
50
+ && command -v infralink-controller-config-consumers \
51
+ && command -v infralink-controller-adapter \
52
+ && command -v infralink-controller-runtime-directories \
53
+ && command -v infralink-controller-host-interface \
54
+ && command -v infralink-controller-doctor \
55
+ && command -v infralink-controller-firewall \
56
+ && command -v infralink-controller-image-resolution \
57
+ && command -v infralink-controller-reference \
58
+ && command -v infralink-controller-template-dependencies
59
+
60
+ CMD ["infralink-ops", "--help"]
@@ -0,0 +1,11 @@
1
+ FROM python:3.12-slim-bookworm
2
+
3
+ WORKDIR /app
4
+ RUN apt-get update \
5
+ && apt-get install --yes --no-install-recommends git \
6
+ && rm -rf /var/lib/apt/lists/*
7
+ COPY pyproject.toml README.md ./
8
+ COPY src ./src
9
+ RUN python -m pip install --disable-pip-version-check .
10
+
11
+ ENTRYPOINT ["infralink-ops"]
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.5
2
+ Name: infralink-ops
3
+ Version: 0.2.67
4
+ Summary: Operational runtime for direct Infralink registry projections
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: infralink<0.7,>=0.6
7
+ Requires-Dist: jinja2>=3.0
8
+ Requires-Dist: pyyaml>=6.0
9
+ Provides-Extra: dev
10
+ Requires-Dist: build>=1.2; extra == 'dev'
11
+ Requires-Dist: pytest>=8.0; extra == 'dev'
12
+ Requires-Dist: ruff>=0.6; extra == 'dev'
13
+ Requires-Dist: twine>=6.0; extra == 'dev'
14
+ Description-Content-Type: text/markdown
15
+
16
+ # Infralink Ops
17
+
18
+ ## BLUF
19
+
20
+ This repo packages the public controller runtime for managed hosts. Deployment
21
+ intent, private templates, and secret aliases remain in the environment
22
+ registry; live-service acceptance remains environment-owned operational state.
23
+
24
+ Use it when you need bounded host primitives for registry checkout, template
25
+ rendering, config projection, Docker image retention, Compose consumer
26
+ activation, firewall verification, secret rendering, or host doctor evidence.
27
+
28
+ Do not use this repo to select fleet desired state. Registry revisions, service
29
+ definitions, image pins, hostnames, and secret bindings come from the
30
+ environment registry.
31
+
32
+ ## Reader Paths
33
+
34
+ | Goal | Start here |
35
+ | --- | --- |
36
+ | Understand the runtime boundary | [Controller runtime guide](docs/controller-runtime-guide.md) |
37
+ | Debug a stale RelayOS staging rollout | [Controller runtime guide](docs/controller-runtime-guide.md#triage-a-stale-host) |
38
+ | Check available CLIs | [`pyproject.toml`](pyproject.toml) |
39
+ | Inspect host-installed launcher assets | [`src/infralink_ops/assets/`](src/infralink_ops/assets/) |
40
+ | Review controller behavior | [`src/infralink_ops/`](src/infralink_ops/) and [`tests/`](tests/) |
41
+
42
+ ## How It Fits
43
+
44
+ ```mermaid
45
+ flowchart LR
46
+ registry["configured registry revision"] --> checkout["/var/lib/infralink/registry"]
47
+ checkout --> render["template render and static config projection"]
48
+ render --> consumers["Compose consumer validate/activate"]
49
+ consumers --> evidence["doctor, metrics, and logs"]
50
+ evidence --> operator["environment-owned acceptance"]
51
+ ```
52
+
53
+ This repo implements the bounded primitives in the middle of the flow. It does
54
+ not own the registry data model or the environment-specific acceptance result.
55
+
56
+ ## Main CLIs
57
+
58
+ | Command | Purpose |
59
+ | --- | --- |
60
+ | `infralink-controller-registry-checkout fetch` | Fetch a declared registry ref into an existing clean checkout. |
61
+ | `infralink-controller-template-render` | Render registry-declared templates from explicit inputs. |
62
+ | `infralink-controller-config-consumers validate\|activate` | Validate or recreate services affected by rendered config changes. |
63
+ | `infralink-controller-images retain-and-prune` | Keep selected immutable Docker images and prune stale cache images. |
64
+ | `infralink-controller-render-secrets` | Resolve registry-declared render-secret bindings through BWS. |
65
+ | `infralink-controller-firewall render\|verify` | Render or verify declared nftables policy. |
66
+ | `infralink-controller-doctor` | Read-only host-runtime check for registry, reconcile, Compose, firewall, and metrics evidence. |
67
+ | `infralink-host doctor\|reconcile\|bootstrap --apply` | Host launcher installed from [`src/infralink_ops/assets/infralink-host`](src/infralink_ops/assets/infralink-host). |
68
+
69
+ Each command is intentionally narrow. Commands receive explicit inputs and
70
+ return bounded machine-readable envelopes where possible.
71
+
72
+ ## Authority Boundary
73
+
74
+ | This repo owns | This repo does not own |
75
+ | --- | --- |
76
+ | Controller image build recipe. | Which registry revision a host should run. |
77
+ | Host launcher and systemd unit assets. | Service definitions, hostnames, DNS, certificates, or image pins. |
78
+ | Runtime primitives with bounded inputs and outputs. | Tenant or application policy. |
79
+ | Doctor and evidence helpers. | Live-service acceptance criteria. |
80
+ | BWS resolution primitive. | BWS secret values or registry secret declarations. |
81
+
82
+ For RelayOS IRC, source/config/image repos feed the registry first:
83
+
84
+ ```mermaid
85
+ flowchart LR
86
+ deploy["relayos-deploy docs and deploy contract"]
87
+ config["relayos-irc-config"]
88
+ modules["custom-modules"]
89
+ images["relayos-irc-containers"]
90
+ registry["infra-registry"]
91
+ ops["infralink-ops controller"]
92
+ host["managed host"]
93
+
94
+ config --> registry
95
+ modules --> images
96
+ images --> deploy
97
+ deploy --> registry
98
+ registry --> ops
99
+ ops --> host
100
+ ```
101
+
102
+ ## GHCR and BWS
103
+
104
+ The controller image publishes to
105
+ [cyberstorm-dev packages](https://github.com/orgs/cyberstorm-dev/packages) as
106
+ `ghcr.io/cyberstorm-dev/infralink-ops-controller`.
107
+
108
+ BWS access is runtime-only. This repo contains the resolver and tests for the
109
+ resolver contract; the token and secret object names belong to the environment
110
+ registry and host runtime.
111
+
112
+ ## Verify Changes
113
+
114
+ Run the same checks Woodpecker runs:
115
+
116
+ ```bash
117
+ python -m pip install --disable-pip-version-check \
118
+ 'infralink @ https://github.com/cyberstorm-dev/infralink/releases/download/v0.6.14/infralink-0.6.14-py3-none-any.whl#sha256=e41e16e082df50d7506785feb40dc3ea48087d46c391e31f2bd77e3ef81ce0e3'
119
+ python -m pip install --disable-pip-version-check -e '.[dev]'
120
+ python -m ruff check src tests
121
+ python -m ruff format --check src tests
122
+ python -m pytest -q
123
+ python -m build
124
+ ```
125
+
126
+ Infralink Ops declares compatibility with Infralink `>=0.6,<0.7`. Until
127
+ Infralink is published to PyPI, bootstrap a released, checksum-pinned wheel
128
+ before installing Ops so a clean environment does not attempt an unavailable
129
+ index resolution.
130
+
131
+ The controller image publish step runs only on `main` pushes. Pull requests use
132
+ Docker buildx dry-run validation.
133
+
134
+ ## Triage A Stale Host
135
+
136
+ Check in this order:
137
+
138
+ 1. Confirm the environment selected the intended registry revision.
139
+ 2. Confirm `/var/lib/infralink/registry` has the expected checkout.
140
+ 3. Run `infralink-host doctor` for read-only host evidence.
141
+ 4. Inspect `/var/lib/infralink/reconcile-result.yml` as the last reconcile
142
+ result, not as desired state.
143
+ 5. Check whether `infralink-host-reconcile.timer` ran after the registry change.
144
+ 6. Check rendered files under `/opt/services/config`.
145
+ 7. Check the affected Compose service or application-specific behavior.
146
+
147
+ Do not repair desired-state drift by editing `/opt/services` directly. Fix the
148
+ registry or source repo that owns the value, then let the controller reconcile.
149
+
150
+ ## Development Contract
151
+
152
+ - Keep commands agent-friendly: explicit inputs, bounded output, stable exit
153
+ behavior, and machine-readable evidence.
154
+ - Keep provider-specific policy out of generic primitives unless the command
155
+ name says it is provider-specific.
156
+ - Add tests for every command contract, runtime boundary, and failure mode.
157
+ - Keep README-level docs focused on operator entrypoints; put command-specific
158
+ details in focused guides or tests.
@@ -0,0 +1,143 @@
1
+ # Infralink Ops
2
+
3
+ ## BLUF
4
+
5
+ This repo packages the public controller runtime for managed hosts. Deployment
6
+ intent, private templates, and secret aliases remain in the environment
7
+ registry; live-service acceptance remains environment-owned operational state.
8
+
9
+ Use it when you need bounded host primitives for registry checkout, template
10
+ rendering, config projection, Docker image retention, Compose consumer
11
+ activation, firewall verification, secret rendering, or host doctor evidence.
12
+
13
+ Do not use this repo to select fleet desired state. Registry revisions, service
14
+ definitions, image pins, hostnames, and secret bindings come from the
15
+ environment registry.
16
+
17
+ ## Reader Paths
18
+
19
+ | Goal | Start here |
20
+ | --- | --- |
21
+ | Understand the runtime boundary | [Controller runtime guide](docs/controller-runtime-guide.md) |
22
+ | Debug a stale RelayOS staging rollout | [Controller runtime guide](docs/controller-runtime-guide.md#triage-a-stale-host) |
23
+ | Check available CLIs | [`pyproject.toml`](pyproject.toml) |
24
+ | Inspect host-installed launcher assets | [`src/infralink_ops/assets/`](src/infralink_ops/assets/) |
25
+ | Review controller behavior | [`src/infralink_ops/`](src/infralink_ops/) and [`tests/`](tests/) |
26
+
27
+ ## How It Fits
28
+
29
+ ```mermaid
30
+ flowchart LR
31
+ registry["configured registry revision"] --> checkout["/var/lib/infralink/registry"]
32
+ checkout --> render["template render and static config projection"]
33
+ render --> consumers["Compose consumer validate/activate"]
34
+ consumers --> evidence["doctor, metrics, and logs"]
35
+ evidence --> operator["environment-owned acceptance"]
36
+ ```
37
+
38
+ This repo implements the bounded primitives in the middle of the flow. It does
39
+ not own the registry data model or the environment-specific acceptance result.
40
+
41
+ ## Main CLIs
42
+
43
+ | Command | Purpose |
44
+ | --- | --- |
45
+ | `infralink-controller-registry-checkout fetch` | Fetch a declared registry ref into an existing clean checkout. |
46
+ | `infralink-controller-template-render` | Render registry-declared templates from explicit inputs. |
47
+ | `infralink-controller-config-consumers validate\|activate` | Validate or recreate services affected by rendered config changes. |
48
+ | `infralink-controller-images retain-and-prune` | Keep selected immutable Docker images and prune stale cache images. |
49
+ | `infralink-controller-render-secrets` | Resolve registry-declared render-secret bindings through BWS. |
50
+ | `infralink-controller-firewall render\|verify` | Render or verify declared nftables policy. |
51
+ | `infralink-controller-doctor` | Read-only host-runtime check for registry, reconcile, Compose, firewall, and metrics evidence. |
52
+ | `infralink-host doctor\|reconcile\|bootstrap --apply` | Host launcher installed from [`src/infralink_ops/assets/infralink-host`](src/infralink_ops/assets/infralink-host). |
53
+
54
+ Each command is intentionally narrow. Commands receive explicit inputs and
55
+ return bounded machine-readable envelopes where possible.
56
+
57
+ ## Authority Boundary
58
+
59
+ | This repo owns | This repo does not own |
60
+ | --- | --- |
61
+ | Controller image build recipe. | Which registry revision a host should run. |
62
+ | Host launcher and systemd unit assets. | Service definitions, hostnames, DNS, certificates, or image pins. |
63
+ | Runtime primitives with bounded inputs and outputs. | Tenant or application policy. |
64
+ | Doctor and evidence helpers. | Live-service acceptance criteria. |
65
+ | BWS resolution primitive. | BWS secret values or registry secret declarations. |
66
+
67
+ For RelayOS IRC, source/config/image repos feed the registry first:
68
+
69
+ ```mermaid
70
+ flowchart LR
71
+ deploy["relayos-deploy docs and deploy contract"]
72
+ config["relayos-irc-config"]
73
+ modules["custom-modules"]
74
+ images["relayos-irc-containers"]
75
+ registry["infra-registry"]
76
+ ops["infralink-ops controller"]
77
+ host["managed host"]
78
+
79
+ config --> registry
80
+ modules --> images
81
+ images --> deploy
82
+ deploy --> registry
83
+ registry --> ops
84
+ ops --> host
85
+ ```
86
+
87
+ ## GHCR and BWS
88
+
89
+ The controller image publishes to
90
+ [cyberstorm-dev packages](https://github.com/orgs/cyberstorm-dev/packages) as
91
+ `ghcr.io/cyberstorm-dev/infralink-ops-controller`.
92
+
93
+ BWS access is runtime-only. This repo contains the resolver and tests for the
94
+ resolver contract; the token and secret object names belong to the environment
95
+ registry and host runtime.
96
+
97
+ ## Verify Changes
98
+
99
+ Run the same checks Woodpecker runs:
100
+
101
+ ```bash
102
+ python -m pip install --disable-pip-version-check \
103
+ 'infralink @ https://github.com/cyberstorm-dev/infralink/releases/download/v0.6.14/infralink-0.6.14-py3-none-any.whl#sha256=e41e16e082df50d7506785feb40dc3ea48087d46c391e31f2bd77e3ef81ce0e3'
104
+ python -m pip install --disable-pip-version-check -e '.[dev]'
105
+ python -m ruff check src tests
106
+ python -m ruff format --check src tests
107
+ python -m pytest -q
108
+ python -m build
109
+ ```
110
+
111
+ Infralink Ops declares compatibility with Infralink `>=0.6,<0.7`. Until
112
+ Infralink is published to PyPI, bootstrap a released, checksum-pinned wheel
113
+ before installing Ops so a clean environment does not attempt an unavailable
114
+ index resolution.
115
+
116
+ The controller image publish step runs only on `main` pushes. Pull requests use
117
+ Docker buildx dry-run validation.
118
+
119
+ ## Triage A Stale Host
120
+
121
+ Check in this order:
122
+
123
+ 1. Confirm the environment selected the intended registry revision.
124
+ 2. Confirm `/var/lib/infralink/registry` has the expected checkout.
125
+ 3. Run `infralink-host doctor` for read-only host evidence.
126
+ 4. Inspect `/var/lib/infralink/reconcile-result.yml` as the last reconcile
127
+ result, not as desired state.
128
+ 5. Check whether `infralink-host-reconcile.timer` ran after the registry change.
129
+ 6. Check rendered files under `/opt/services/config`.
130
+ 7. Check the affected Compose service or application-specific behavior.
131
+
132
+ Do not repair desired-state drift by editing `/opt/services` directly. Fix the
133
+ registry or source repo that owns the value, then let the controller reconcile.
134
+
135
+ ## Development Contract
136
+
137
+ - Keep commands agent-friendly: explicit inputs, bounded output, stable exit
138
+ behavior, and machine-readable evidence.
139
+ - Keep provider-specific policy out of generic primitives unless the command
140
+ name says it is provider-specific.
141
+ - Add tests for every command contract, runtime boundary, and failure mode.
142
+ - Keep README-level docs focused on operator entrypoints; put command-specific
143
+ details in focused guides or tests.
@@ -0,0 +1,72 @@
1
+ # Infralink Ops controller runtime guide
2
+
3
+ ## BLUF
4
+
5
+ Use this guide to understand what the host controller can do and what
6
+ evidence it can produce.
7
+
8
+ The controller applies a registry revision that another layer selected. It does
9
+ not choose tenant config, image digests, secrets, DNS, or service policy.
10
+
11
+ ## Runtime Lifecycle
12
+
13
+ ```mermaid
14
+ sequenceDiagram
15
+ participant Registry as Registry declaration
16
+ participant Host as infralink-host-reconcile.timer
17
+ participant Checkout as /var/lib/infralink/registry
18
+ participant Render as Template and config projection
19
+ participant Compose as Compose consumers
20
+ participant Evidence as Doctor and metrics
21
+
22
+ Registry->>Host: configured revision and controller image
23
+ Host->>Checkout: fetch explicit ref
24
+ Host->>Render: render templates and materialize config trees
25
+ Render->>Compose: validate affected consumers
26
+ Compose->>Compose: activate changed services
27
+ Compose->>Evidence: publish reconcile result
28
+ ```
29
+
30
+ ## Controller Primitives
31
+
32
+ | Primitive | Command | Evidence |
33
+ | --- | --- | --- |
34
+ | Registry checkout | `infralink-controller-registry-checkout fetch` | Detached registry revision. |
35
+ | Template rendering | `infralink-controller-template-render` | Rendered files from explicit inputs. |
36
+ | Static config trees | `materialize_config_tree` | Changed paths below the declared target. |
37
+ | Compose consumers | `infralink-controller-config-consumers validate\|activate` | Affected consumers and services. |
38
+ | Image retention | `infralink-controller-images retain-and-prune` | Selected immutable image retained; stale cache images pruned. |
39
+ | Secrets | `infralink-controller-render-secrets` | BWS-backed rendered values without committing secrets. |
40
+ | Firewall | `infralink-controller-firewall render\|verify` | Declared nftables table or runtime drift result. |
41
+ | Doctor | `infralink-controller-doctor` | Read-only host consistency envelope. |
42
+
43
+ ## BWS Contract
44
+
45
+ The controller can resolve registry-declared BWS bindings at runtime. It must
46
+ not commit secret values, print tokens, or infer undeclared secret names.
47
+
48
+ Failure to resolve BWS is a registry/runtime failure. Do not fix it by hardcoding
49
+ a value into source, rendered config, or a Compose file.
50
+
51
+ ## GHCR Contract
52
+
53
+ Woodpecker publishes the controller image to
54
+ [cyberstorm-dev packages](https://github.com/orgs/cyberstorm-dev/packages) as
55
+ `ghcr.io/cyberstorm-dev/infralink-ops-controller` on `main` pushes.
56
+
57
+ Use immutable `sha-<short-sha>` tags or digests for evidence. Do not use `head` or `main` as acceptance evidence.
58
+
59
+ ## Triage A Stale Host
60
+
61
+ 1. Confirm the registry revision that the environment intended to run.
62
+ 2. Confirm `/var/lib/infralink/registry` resolved to that revision.
63
+ 3. Run `infralink-host doctor`.
64
+ 4. Check `systemctl status infralink-host-reconcile.timer`.
65
+ 5. Inspect `/var/lib/infralink/reconcile-result.yml` for the last reconcile
66
+ evidence.
67
+ 6. Inspect rendered files under `/opt/services/config`.
68
+ 7. Check the live service using environment-owned acceptance criteria.
69
+
70
+ If evidence points to a wrong source value, fix the owning source repository or
71
+ registry declaration. If evidence points to controller behavior, fix this repo
72
+ with tests and publish a new controller image.