Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
2e069dd
This is currently very broken.
magiccodingman Jul 24, 2026
656fc5c
double await fix
magiccodingman Jul 24, 2026
54bca09
Add .NET 10 migration build workflow
magiccodingman Jul 24, 2026
ee37edf
Run migration build for pull requests
magiccodingman Jul 24, 2026
b7fdea3
Update CI validation for .NET 10
magiccodingman Jul 24, 2026
64159d2
Capture complete .NET 10 build diagnostics
magiccodingman Jul 24, 2026
2278b01
Migrate metrics charts to MudBlazor 9
magiccodingman Jul 24, 2026
e260818
Automate the next MudBlazor migration fixes
magiccodingman Jul 24, 2026
df5c3b5
Fix MudBlazor 9 chart, dialog, and grid APIs
github-actions[bot] Jul 24, 2026
d86c43f
Run migration patches against the repair branch
magiccodingman Jul 24, 2026
aff0a36
Capture complete .NET 10 test diagnostics
magiccodingman Jul 24, 2026
081c453
Retarget TLS tests to .NET 10
magiccodingman Jul 24, 2026
00ef468
Migrate domain backup file upload to MudBlazor 9
magiccodingman Jul 24, 2026
74cbeb3
Apply remaining MudBlazor 9 component migrations
magiccodingman Jul 24, 2026
c7986e8
Add temporary compiler-driven migration script
magiccodingman Jul 24, 2026
1a6726c
Run migration fixes from a standalone script
magiccodingman Jul 24, 2026
db4d5c8
Finish MudBlazor 9 form and component migrations
github-actions[bot] Jul 24, 2026
190af2f
Update .NET 10 test host packages
magiccodingman Jul 24, 2026
19b9840
Add .NET 10 test-host diagnostics
magiccodingman Jul 24, 2026
cbc586d
Restore TLS test project explicitly
magiccodingman Jul 24, 2026
cf00904
Migrate add-ban validation to async MudForm APIs
magiccodingman Jul 24, 2026
362294c
Migrate add-user validation to async MudForm APIs
magiccodingman Jul 24, 2026
baec649
Migrate password validation to async MudForm APIs
magiccodingman Jul 24, 2026
9018aff
Migrate domain validation to async MudForm APIs
magiccodingman Jul 24, 2026
10596be
Pin patched SQLite native bundle
magiccodingman Jul 24, 2026
0b3fb9a
Finalize .NET 10 TLS validation workflow
magiccodingman Jul 24, 2026
2b4b2e0
Remove temporary migration build workflow
magiccodingman Jul 24, 2026
c36e6a5
Remove temporary migration helper script
magiccodingman Jul 24, 2026
39adf11
Document explicit TLS test restore
magiccodingman Jul 24, 2026
e42b7d1
Merge pull request #11 from magiccodingman/agent/net10-mudblazor-migr…
magiccodingman Jul 24, 2026
98bc2d7
Merge pull request #12 from magiccodingman/magiccodingman/net10
magiccodingman Jul 24, 2026
00f19e8
Add multi-stage Docker appliance image
magiccodingman Jul 24, 2026
56e8041
Add appliance process supervisor
magiccodingman Jul 24, 2026
c74db8a
Add container health check
magiccodingman Jul 24, 2026
806dfd6
Add production Compose appliance
magiccodingman Jul 24, 2026
82a2142
Add Docker development override
magiccodingman Jul 24, 2026
983a801
Add Docker environment template
magiccodingman Jul 24, 2026
1c6c540
Add Docker build exclusions
magiccodingman Jul 24, 2026
5d8a1a0
Ignore local appliance state
magiccodingman Jul 24, 2026
a4615dd
Document Docker appliance architecture
magiccodingman Jul 24, 2026
1769e83
Document Docker quick start
magiccodingman Jul 24, 2026
539a64a
Generate a secure Docker bootstrap admin password
magiccodingman Jul 24, 2026
e691336
Separate persistent database storage
magiccodingman Jul 24, 2026
e847ca5
Add multi-platform Docker CI and publishing
magiccodingman Jul 24, 2026
58cd020
Preserve Docker build diagnostics
magiccodingman Jul 24, 2026
4ca64b4
Reuse existing base image groups safely
magiccodingman Jul 24, 2026
e0f6366
Use the runtime user's numeric primary group
magiccodingman Jul 24, 2026
3ed41df
Cross-compile .NET efficiently for multi-arch images
magiccodingman Jul 24, 2026
74b50b1
Validate the appliance natively on AMD64 and ARM64
magiccodingman Jul 24, 2026
0751619
Read protected state inside the smoke-test container
magiccodingman Jul 24, 2026
051d16e
Add Rider-friendly merged development compose file
magiccodingman Jul 24, 2026
98412db
Add PowerShell Rider Compose generator
magiccodingman Jul 24, 2026
2fcdaea
Add shell Rider Compose generator
magiccodingman Jul 24, 2026
c6b5f3a
Document Rider Compose generation
magiccodingman Jul 24, 2026
aa8cd87
Rename merged development compose file
magiccodingman Jul 24, 2026
0f54cf9
Remove Rider-specific merged compose name
magiccodingman Jul 24, 2026
ddc144b
Generate generic merged development compose file
magiccodingman Jul 24, 2026
bfa00d1
Generate generic merged development compose file
magiccodingman Jul 24, 2026
98d8a73
Document generic generated development compose file
magiccodingman Jul 24, 2026
31d3481
Remove generated development compose workaround
magiccodingman Jul 24, 2026
5ee2482
Remove obsolete Rider compose generator
magiccodingman Jul 24, 2026
b51a6f4
Remove obsolete Rider compose generator
magiccodingman Jul 24, 2026
461dbda
Remove obsolete generated compose documentation
magiccodingman Jul 24, 2026
2ebef1a
Fix Rider development container runtime paths
magiccodingman Jul 24, 2026
a93a8c4
Fix development NuGet directory ownership
magiccodingman Jul 24, 2026
e9ac0a2
Add Kubo diagnostics command
magiccodingman Jul 24, 2026
1dc2eb1
Install Kubo configuration tooling
magiccodingman Jul 24, 2026
b55b0d9
Expose managed Kubo overrides
magiccodingman Jul 24, 2026
280002d
Document Kubo server overrides
magiccodingman Jul 24, 2026
72f7902
Configure Kubo as a public server
magiccodingman Jul 24, 2026
0c042d0
Wire Kubo server configuration into images
magiccodingman Jul 24, 2026
f51b4c8
Apply managed Kubo configuration at startup
magiccodingman Jul 24, 2026
468c7c0
Validate managed Kubo server defaults in CI
magiccodingman Jul 24, 2026
969be3b
Document managed Kubo server behavior
magiccodingman Jul 24, 2026
fca02c6
Use canonical Kubo JSON config syntax
magiccodingman Jul 24, 2026
f26d844
Use canonical Kubo JSON config syntax
magiccodingman Jul 24, 2026
f6f3f98
Use canonical Kubo JSON config syntax in CI
magiccodingman Jul 24, 2026
03497f1
Describe Kubo server defaults in README
magiccodingman Jul 24, 2026
c426e5e
Migrate existing Kubo repos before configuration
magiccodingman Jul 24, 2026
3d0b0f3
Test automatic Kubo repository migration
magiccodingman Jul 24, 2026
065cc37
Fix migration version assertion
magiccodingman Jul 24, 2026
50bbb6f
Simplify migrated repo version check
magiccodingman Jul 24, 2026
9f36208
Fix legacy repo test ownership
magiccodingman Jul 24, 2026
dbae600
Read legacy repo metadata before ownership handoff
magiccodingman Jul 24, 2026
28147d6
Let authenticated users access the TruthGate portal
magiccodingman Jul 24, 2026
67c1270
Test authenticated portal bypass for mapped domains
magiccodingman Jul 24, 2026
7cf8bb1
Revert authenticated domain gateway bypass
magiccodingman Jul 24, 2026
0f55ef8
Remove invalid domain gateway regression test
magiccodingman Jul 24, 2026
1287e78
Include Blazor web assets in production publish
magiccodingman Jul 25, 2026
ed2986e
Fail Docker builds without Blazor bootstrap assets
magiccodingman Jul 25, 2026
cb93239
Merge pull request #13 from magiccodingman/agent/docker-appliance
magiccodingman Jul 25, 2026
b0f40ba
Extract reusable Docker appliance CI
magiccodingman Jul 25, 2026
b4ff523
Reuse Docker appliance CI before GHCR publishing
magiccodingman Jul 25, 2026
4c4be06
Add gated Docker Hub stable release workflow
magiccodingman Jul 25, 2026
d61676e
Make repository migration tests reusable
magiccodingman Jul 25, 2026
06cea5f
Make TLS lifecycle tests reusable
magiccodingman Jul 25, 2026
5d99129
Set initial stable release series
magiccodingman Jul 25, 2026
56cdd47
Default Compose to Docker Hub stable image
magiccodingman Jul 25, 2026
271454f
Point example configuration at stable image
magiccodingman Jul 25, 2026
3fab15b
Document the stable Docker Hub image flow
magiccodingman Jul 25, 2026
8f0a7d2
Document automatic stable release tags
magiccodingman Jul 25, 2026
95580c1
Merge pull request #15 from magiccodingman/agent/dockerhub-stable-rel…
magiccodingman Jul 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.git
.github
.idea
.vs
.env
.env.*
!.env.example
**/bin
**/obj
**/TestResults
**/*.user
**/*.suo
coverage
artifacts
data
Test.TruthGate
TruthGate-Web/TruthGate-Web.Tests
55 changes: 55 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Tested multi-platform release. Override this to pin a version or use a local image.
TRUTHGATE_IMAGE=magiccodingman/truthgate-ipfs:stable

# Build inputs. Both official base images are multi-platform.
DOTNET_VERSION=10.0
KUBO_VERSION=v0.42.0
TRUTHGATE_UID=1000
TRUTHGATE_GID=1000

# Host ports.
TRUTHGATE_HTTP_PORT=80
TRUTHGATE_HTTPS_PORT=443
TRUTHGATE_DEV_HTTP_PORT=8080
IPFS_SWARM_PORT=4001

# Persistent host paths. The blockstore is always separate so it can later be
# moved to different storage without changing the container's Kubo layout.
TRUTHGATE_DATA_HOST_PATH=./data/truthgate
IPFS_REPO_HOST_PATH=./data/ipfs/repo
IPFS_BLOCKS_HOST_PATH=./data/ipfs/blocks

# Certificate behavior.
TRUTHGATE_ACME_STAGING=false
# Optional comma-separated IP addresses for the self-signed fallback cert.
TRUTHGATE_CERT_IPS=

# TruthGate creates data/truthgate/config/kubo-settings.json on first boot.
# That persistent file contains the normal server defaults and is the future
# control-plane contract for the TruthGate UI. Uncomment any value below to
# override the corresponding persistent setting from Docker/Compose.
#
# TRUTHGATE_KUBO_APPLY_SERVER_PROFILE=true
# TRUTHGATE_KUBO_ENSURE_SWARM_LISTENERS=true
# TRUTHGATE_KUBO_ROUTING_TYPE=dhtserver
# TRUTHGATE_KUBO_HOLE_PUNCHING=true
# TRUTHGATE_KUBO_RELAY_CLIENT=true
# TRUTHGATE_KUBO_PROVIDE_ENABLED=true
# TRUTHGATE_KUBO_PROVIDE_STRATEGY=all
# TRUTHGATE_KUBO_PROVIDE_INTERVAL=22h
# TRUTHGATE_KUBO_PROVIDE_SWEEP=true
# TRUTHGATE_KUBO_PROVIDE_RESUME=true
#
# Storage can be "auto" or any Kubo size such as 750GB, 2TB, or 5TiB.
# Auto uses the configured percentage of the filesystem containing the blockstore.
# TRUTHGATE_KUBO_STORAGE_MAX=auto
# TRUTHGATE_KUBO_STORAGE_PERCENT=90
# TRUTHGATE_KUBO_STORAGE_FALLBACK=200GB
# TRUTHGATE_KUBO_STORAGE_GC_WATERMARK=90
# TRUTHGATE_KUBO_ENABLE_GC=true
#
# Public addresses can be "auto", "off", or a literal address. The announce
# port defaults to IPFS_SWARM_PORT so non-default Docker host mappings work.
# TRUTHGATE_KUBO_PUBLIC_IPV4=auto
# TRUTHGATE_KUBO_PUBLIC_IPV6=auto
# TRUTHGATE_KUBO_ANNOUNCE_PORT=4001
235 changes: 235 additions & 0 deletions .github/workflows/docker-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
name: Reusable Docker appliance CI

on:
workflow_call:

permissions:
contents: read

jobs:
validate-compose:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4

- name: Validate production Compose
run: docker compose -f compose.yaml config

- name: Validate development override
run: docker compose -f compose.yaml -f compose.dev.yaml config

- name: Validate container scripts
run: |
bash -n docker/entrypoint.sh
bash -n docker/healthcheck.sh
bash -n docker/kubo-configure.sh
bash -n docker/kubo-status.sh

smoke-test:
strategy:
fail-fast: false
matrix:
include:
- architecture: amd64
runner: ubuntu-24.04
- architecture: arm64
runner: ubuntu-24.04-arm

runs-on: ${{ matrix.runner }}

steps:
- uses: actions/checkout@v4

- name: Build production image (${{ matrix.architecture }})
shell: bash
run: |
set -o pipefail
docker build \
--progress=plain \
--platform linux/${{ matrix.architecture }} \
--target production \
--tag truthgate-ipfs:test-${{ matrix.architecture }} \
. 2>&1 | tee production-image-build-${{ matrix.architecture }}.log

- name: Upload production build diagnostics
if: always()
uses: actions/upload-artifact@v4
with:
name: production-image-build-${{ matrix.architecture }}
path: production-image-build-${{ matrix.architecture }}.log
if-no-files-found: error

- name: Build development image (${{ matrix.architecture }})
shell: bash
run: |
set -o pipefail
docker build \
--progress=plain \
--platform linux/${{ matrix.architecture }} \
--target development \
--tag truthgate-ipfs:dev-test-${{ matrix.architecture }} \
. 2>&1 | tee development-image-build-${{ matrix.architecture }}.log

- name: Upload development build diagnostics
if: always()
uses: actions/upload-artifact@v4
with:
name: development-image-build-${{ matrix.architecture }}
path: development-image-build-${{ matrix.architecture }}.log
if-no-files-found: ignore

- name: Start, replace, and revalidate the appliance
shell: bash
run: |
exec > >(tee runtime-smoke-${{ matrix.architecture }}.log) 2>&1
set -Eeuo pipefail

export TRUTHGATE_IMAGE=truthgate-ipfs:test-${{ matrix.architecture }}
export TRUTHGATE_HTTP_PORT=18080
export TRUTHGATE_HTTPS_PORT=18443
export IPFS_SWARM_PORT=14001
export TRUTHGATE_KUBO_PUBLIC_IPV4=off
export TRUTHGATE_KUBO_PUBLIC_IPV6=off
export TRUTHGATE_DATA_HOST_PATH=./.ci-data/truthgate
export IPFS_REPO_HOST_PATH=./.ci-data/ipfs/repo
export IPFS_BLOCKS_HOST_PATH=./.ci-data/ipfs/blocks

cleanup() {
docker compose logs --no-color 2>/dev/null || true
docker compose down --remove-orphans 2>/dev/null || true
}
trap cleanup EXIT

wait_for_health() {
for attempt in $(seq 1 60); do
status="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' truthgate)"
if [[ "${status}" == "healthy" ]]; then
return 0
fi

if [[ "${status}" == "unhealthy" ]]; then
echo "TruthGate became unhealthy."
return 1
fi

sleep 5
done

echo "TruthGate did not become healthy in time."
return 1
}

read_peer_id() {
docker exec truthgate \
ipfs --api=/ip4/127.0.0.1/tcp/5001 id \
| python3 -c 'import json, sys; print(json.load(sys.stdin)["ID"])'
}

read_bootstrap_hash() {
docker exec truthgate \
sha256sum /data/truthgate/state/bootstrap-admin-password \
| cut -d' ' -f1
}

read_settings_hash() {
docker exec truthgate \
sha256sum /data/truthgate/config/kubo-settings.json \
| cut -d' ' -f1
}

validate_truthgate_portal() {
local asset=/tmp/truthgate-blazor.web.js

curl \
--silent \
--show-error \
--fail \
--insecure \
--header 'Accept-Encoding: identity' \
--output "${asset}" \
https://127.0.0.1:18443/_framework/blazor.web.js

local size
size="$(wc -c <"${asset}")"
echo "Blazor bootstrap size: ${size} bytes"
test "${size}" -gt 10000
}

validate_kubo_server_defaults() {
test "$(docker exec truthgate ipfs config Routing.Type)" = "dhtserver"
test "$(docker exec truthgate ipfs config Swarm.EnableHolePunching)" = "true"
test "$(docker exec truthgate ipfs config Swarm.RelayClient.Enabled)" = "true"
test "$(docker exec truthgate ipfs config Provide.Enabled)" = "true"
test "$(docker exec truthgate ipfs config Provide.Strategy)" = "all"
test "$(docker exec truthgate ipfs config Provide.DHT.Interval)" = "22h"
test "$(docker exec truthgate ipfs config Provide.DHT.SweepEnabled)" = "true"
test "$(docker exec truthgate ipfs config Provide.DHT.ResumeEnabled)" = "true"
test "$(docker exec truthgate ipfs config Datastore.StorageGCWatermark)" = "90"

storage_max="$(docker exec truthgate ipfs config Datastore.StorageMax)"
test "${storage_max}" != "10GB"
[[ "${storage_max}" =~ ^[0-9]+B$ ]]

docker exec truthgate test -s /data/truthgate/state/kubo-server-profile-v1
docker exec truthgate test -s /data/truthgate/config/kubo-settings.json
docker exec truthgate test -s /data/truthgate/config/kubo-overrides.json

docker exec truthgate \
ipfs config --json Addresses.Swarm \
| jq -e '
index("/ip4/0.0.0.0/tcp/4001") and
index("/ip6/::/tcp/4001") and
index("/ip4/0.0.0.0/udp/4001/quic-v1") and
index("/ip4/0.0.0.0/udp/4001/quic-v1/webtransport") and
index("/ip6/::/udp/4001/quic-v1") and
index("/ip6/::/udp/4001/quic-v1/webtransport")
'

test "$(docker exec truthgate ipfs config Addresses.API)" = "/ip4/127.0.0.1/tcp/5001"
test "$(docker exec truthgate ipfs config Addresses.Gateway)" = "/ip4/127.0.0.1/tcp/9010"
docker exec truthgate truthgate-kubo-status
}

mkdir -p .ci-data/truthgate .ci-data/ipfs/repo .ci-data/ipfs/blocks

docker compose up --detach --no-build
wait_for_health

# Read protected state from inside the container. The host runner is
# intentionally unable to inspect the bootstrap secret directly.
docker exec truthgate test -s /data/ipfs/repo/config
docker exec truthgate test -s /data/truthgate/state/bootstrap-admin-password
validate_truthgate_portal
validate_kubo_server_defaults
peer_id_before="$(read_peer_id)"
bootstrap_hash_before="$(read_bootstrap_hash)"
settings_hash_before="$(read_settings_hash)"

# Replace the container while retaining only the documented bind-mounted
# state. Kubo identity, managed settings, and first-run credentials must
# remain stable.
docker compose down --remove-orphans
docker compose up --detach --no-build
wait_for_health

docker exec truthgate test -s /data/ipfs/repo/config
docker exec truthgate test -s /data/truthgate/state/bootstrap-admin-password
validate_truthgate_portal
validate_kubo_server_defaults
peer_id_after="$(read_peer_id)"
bootstrap_hash_after="$(read_bootstrap_hash)"
settings_hash_after="$(read_settings_hash)"

test "${peer_id_before}" = "${peer_id_after}"
test "${bootstrap_hash_before}" = "${bootstrap_hash_after}"
test "${settings_hash_before}" = "${settings_hash_after}"

docker compose logs --no-color

- name: Upload runtime diagnostics
if: always()
uses: actions/upload-artifact@v4
with:
name: runtime-smoke-${{ matrix.architecture }}
path: runtime-smoke-${{ matrix.architecture }}.log
if-no-files-found: ignore
Loading
Loading