release(v1.7.0-alpha): bump + fix git-method update + reconciler creates
Two fixes bundled into the OTA: 1. update.download hard-fail on git-path nodes. handle_update_check's git branch reported update_available=true + update_method="git" but never populated state.available_update, so update.download returned "No update available to download" even though the UI showed one. SystemUpdate.vue now routes update_method=="git" through update.git-apply (pull+rebuild+ restart via self-update.sh); manifest-path nodes keep the download→apply flow. i18n strings + confirm modal added for the git path. 2. Reconciler creating containers behind the user's back. On fresh unbundled installs (.198, .253) archy-mempool-db and archy-btcpay-db materialised ~10 min after first boot because reconcile-containers.sh walked container-specs.sh's canonical tier list and created any "missing" container. reset_spec() now defaults SPEC_OPTIONAL="true", so reconcile is strictly a repair tool — baseline comes from first-boot-containers.sh (filebrowser on unbundled), everything else from the install RPC. Also forces OTA trigger for nodes on 1.6.0-alpha that otherwise saw "I'm at manifest.version, nothing to do" and skipped the refreshed 1.6 artifacts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2
core/Cargo.lock
generated
2
core/Cargo.lock
generated
@@ -80,7 +80,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "archipelago"
|
||||
version = "1.6.0-alpha"
|
||||
version = "1.7.0-alpha"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"archipelago-container",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "archipelago"
|
||||
version = "1.6.0-alpha"
|
||||
version = "1.7.0-alpha"
|
||||
edition = "2021"
|
||||
description = "Archipelago Bitcoin Node OS - Native backend"
|
||||
authors = ["Archipelago Team"]
|
||||
|
||||
@@ -683,7 +683,12 @@
|
||||
"applySuccess": "Update applied. The service will restart momentarily.",
|
||||
"applyFailed": "Failed to apply update. You can try again or rollback.",
|
||||
"rollbackSuccess": "Rolled back to previous version. Service will restart.",
|
||||
"rollbackFailed": "Rollback failed."
|
||||
"rollbackFailed": "Rollback failed.",
|
||||
"pullAndRebuild": "Pull & Rebuild",
|
||||
"gitMethodHint": "This node builds from source. Update will git-pull, rebuild the backend and UI, then restart — takes a few minutes.",
|
||||
"gitApplyTitle": "Pull & Rebuild?",
|
||||
"gitApplyMessage": "Archipelago will pull the latest code, rebuild, and restart. This can take several minutes and the UI will be briefly unavailable.",
|
||||
"gitApplyStarted": "Update started. The backend will rebuild and restart — this can take a few minutes."
|
||||
},
|
||||
"kiosk": {
|
||||
"pressEsc": "Press ESC to exit",
|
||||
|
||||
@@ -682,7 +682,12 @@
|
||||
"applySuccess": "Actualizaci\u00f3n aplicada. El servicio se reiniciar\u00e1 en un momento.",
|
||||
"applyFailed": "Error al aplicar la actualizaci\u00f3n. Puede intentar de nuevo o revertir.",
|
||||
"rollbackSuccess": "Se revirti\u00f3 a la versi\u00f3n anterior. El servicio se reiniciar\u00e1.",
|
||||
"rollbackFailed": "Error al revertir."
|
||||
"rollbackFailed": "Error al revertir.",
|
||||
"pullAndRebuild": "Pull y Recompilar",
|
||||
"gitMethodHint": "Este nodo compila desde el c\u00f3digo fuente. La actualizaci\u00f3n har\u00e1 git-pull, recompilar\u00e1 y reiniciar\u00e1 — tarda unos minutos.",
|
||||
"gitApplyTitle": "\u00bfPull y Recompilar?",
|
||||
"gitApplyMessage": "Archipelago descargar\u00e1 el c\u00f3digo m\u00e1s reciente, lo compilar\u00e1 y reiniciar\u00e1. Puede tardar varios minutos y la UI estar\u00e1 brevemente no disponible.",
|
||||
"gitApplyStarted": "Actualizaci\u00f3n iniciada. El backend se recompilar\u00e1 y reiniciar\u00e1 — puede tardar unos minutos."
|
||||
},
|
||||
"kiosk": {
|
||||
"pressEsc": "Presione ESC para salir",
|
||||
|
||||
@@ -64,21 +64,33 @@
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="flex gap-3">
|
||||
<!-- Git path: one-shot pull+rebuild+restart -->
|
||||
<button
|
||||
v-if="!downloading && !applying"
|
||||
v-if="updateMethod === 'git' && !applying"
|
||||
@click="requestGitApply"
|
||||
class="glass-button rounded-lg px-6 py-2 text-sm font-medium bg-orange-500/20 border-orange-400/30"
|
||||
>
|
||||
{{ t('systemUpdate.pullAndRebuild') }}
|
||||
</button>
|
||||
<!-- Manifest path: download then apply -->
|
||||
<button
|
||||
v-if="updateMethod !== 'git' && !downloading && !applying && !downloaded"
|
||||
@click="downloadUpdate"
|
||||
class="glass-button rounded-lg px-6 py-2 text-sm font-medium"
|
||||
>
|
||||
{{ t('systemUpdate.downloadUpdate') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="downloaded && !applying"
|
||||
v-if="updateMethod !== 'git' && downloaded && !applying"
|
||||
@click="requestApply"
|
||||
class="glass-button rounded-lg px-6 py-2 text-sm font-medium bg-orange-500/20 border-orange-400/30"
|
||||
>
|
||||
{{ t('systemUpdate.applyUpdate') }}
|
||||
</button>
|
||||
</div>
|
||||
<p v-if="updateMethod === 'git'" class="text-xs text-white/40 mt-3">
|
||||
{{ t('systemUpdate.gitMethodHint') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- No update available -->
|
||||
@@ -169,12 +181,18 @@
|
||||
<div v-if="confirmAction" class="fixed inset-0 z-50 flex items-center justify-center bg-black/10 backdrop-blur-md" @click.self="cancelConfirm">
|
||||
<div class="glass-card p-6 max-w-sm w-full mx-4">
|
||||
<h3 class="text-lg font-semibold text-white mb-3">
|
||||
{{ confirmAction === 'apply' ? t('systemUpdate.applyTitle') : t('systemUpdate.rollbackTitle') }}
|
||||
{{ confirmAction === 'rollback'
|
||||
? t('systemUpdate.rollbackTitle')
|
||||
: confirmAction === 'git-apply'
|
||||
? t('systemUpdate.gitApplyTitle')
|
||||
: t('systemUpdate.applyTitle') }}
|
||||
</h3>
|
||||
<p class="text-sm text-white/70 mb-6">
|
||||
{{ confirmAction === 'apply'
|
||||
? t('systemUpdate.applyMessage')
|
||||
: t('systemUpdate.rollbackMessage') }}
|
||||
{{ confirmAction === 'rollback'
|
||||
? t('systemUpdate.rollbackMessage')
|
||||
: confirmAction === 'git-apply'
|
||||
? t('systemUpdate.gitApplyMessage')
|
||||
: t('systemUpdate.applyMessage') }}
|
||||
</p>
|
||||
<div class="flex gap-3 justify-end">
|
||||
<button @click="cancelConfirm" class="glass-button rounded-lg px-4 py-2 text-sm font-medium">
|
||||
@@ -185,7 +203,11 @@
|
||||
class="glass-button rounded-lg px-4 py-2 text-sm font-medium"
|
||||
:class="confirmAction === 'rollback' ? 'bg-red-500/20 border-red-400/30' : 'bg-orange-500/20 border-orange-400/30'"
|
||||
>
|
||||
{{ confirmAction === 'apply' ? t('systemUpdate.applyNow') : t('systemUpdate.rollbackButton') }}
|
||||
{{ confirmAction === 'rollback'
|
||||
? t('systemUpdate.rollbackButton')
|
||||
: confirmAction === 'git-apply'
|
||||
? t('systemUpdate.pullAndRebuild')
|
||||
: t('systemUpdate.applyNow') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -222,10 +244,11 @@ const loading = ref(false)
|
||||
const downloading = ref(false)
|
||||
const downloaded = ref(false)
|
||||
const applying = ref(false)
|
||||
const confirmAction = ref<'apply' | 'rollback' | null>(null)
|
||||
const confirmAction = ref<'apply' | 'git-apply' | 'rollback' | null>(null)
|
||||
const currentVersion = ref('0.0.0')
|
||||
const lastCheck = ref<string | null>(null)
|
||||
const updateInfo = ref<UpdateDetail | null>(null)
|
||||
const updateMethod = ref<'git' | 'manifest' | null>(null)
|
||||
const rollbackAvailable = ref(false)
|
||||
const updateInProgress = ref(false)
|
||||
const statusMessage = ref('')
|
||||
@@ -299,10 +322,12 @@ async function checkForUpdates() {
|
||||
last_check: string | null
|
||||
update_available: boolean
|
||||
update: UpdateDetail | null
|
||||
update_method?: string
|
||||
}>({ method: 'update.check' })
|
||||
currentVersion.value = res.current_version
|
||||
lastCheck.value = res.last_check
|
||||
updateInfo.value = res.update
|
||||
updateMethod.value = res.update_method === 'git' ? 'git' : 'manifest'
|
||||
if (!res.update_available) {
|
||||
showStatus(t('systemUpdate.upToDateMessage'))
|
||||
}
|
||||
@@ -349,6 +374,10 @@ function requestApply() {
|
||||
confirmAction.value = 'apply'
|
||||
}
|
||||
|
||||
function requestGitApply() {
|
||||
confirmAction.value = 'git-apply'
|
||||
}
|
||||
|
||||
function requestRollback() {
|
||||
confirmAction.value = 'rollback'
|
||||
}
|
||||
@@ -358,15 +387,32 @@ function cancelConfirm() {
|
||||
}
|
||||
|
||||
async function executeConfirm() {
|
||||
if (confirmAction.value === 'apply') {
|
||||
confirmAction.value = null
|
||||
const action = confirmAction.value
|
||||
confirmAction.value = null
|
||||
if (action === 'apply') {
|
||||
await applyUpdate()
|
||||
} else if (confirmAction.value === 'rollback') {
|
||||
confirmAction.value = null
|
||||
} else if (action === 'git-apply') {
|
||||
await applyUpdateGit()
|
||||
} else if (action === 'rollback') {
|
||||
await rollbackUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
async function applyUpdateGit() {
|
||||
applying.value = true
|
||||
statusMessage.value = ''
|
||||
try {
|
||||
await rpcClient.call({ method: 'update.git-apply' })
|
||||
showStatus(t('systemUpdate.gitApplyStarted'))
|
||||
updateInfo.value = null
|
||||
} catch (e) {
|
||||
showStatus(t('systemUpdate.applyFailed'), true)
|
||||
if (import.meta.env.DEV) console.warn('Git apply failed', e)
|
||||
} finally {
|
||||
applying.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function applyUpdate() {
|
||||
applying.value = true
|
||||
statusMessage.value = ''
|
||||
|
||||
@@ -1,34 +1,28 @@
|
||||
{
|
||||
"version": "1.6.0-alpha",
|
||||
"release_date": "2026-04-19",
|
||||
"version": "1.7.0-alpha",
|
||||
"release_date": "2026-04-20",
|
||||
"changelog": [
|
||||
"Bulletproof FIPS from install — no Activate button needed. archipelago auto-starts the FIPS daemon once the seed-derived key exists on disk.",
|
||||
"fips_key written as bech32 nsec (upstream fips daemon format). Auto-migrates legacy raw-byte files from v1.5.0-alpha on first load so existing installs self-heal on this OTA update.",
|
||||
"fips.yaml schema updated to match upstream jmcorgan/fips 0.3+ (`node.identity.persistent: true`, `transports.udp.bind_addr`). Old schema made the daemon crashloop with 'data did not match any variant of untagged enum TransportInstances'.",
|
||||
"ISO: archipelago-fips / archipelago-wg / archipelago-wg-address services no longer masked — ConditionPathExists gates them quietly pre-onboarding. nostr-vpn stays masked (deprecated).",
|
||||
"ISO: persistent journalctl (500M cap) so install, first-boot, and onboarding history survive reboots for post-mortem diagnosis.",
|
||||
"ISO build: verify_backend_version() refuses to ship a binary whose embedded version doesn't match core/archipelago/Cargo.toml. Catches the stale-local-build regression that shipped v1.4.0 binaries inside v1.5.0-alpha ISOs.",
|
||||
"ISO build: installer-env script passed as a bind-mounted file instead of inline `bash -c '…'` — works around a podman/overlay edge case that bricked every rebuild today at debootstrap's first tar extraction.",
|
||||
"VPN status UI: shows 'Not configured' instead of 'Starting…' when no VPN peer has been added yet (wg0 legitimately isn't up; 'Starting' implied something was broken).",
|
||||
"FIPS auto-activates the moment the seed-derived fips_key materialises at onboarding end — no Activate click on fresh installs, even before the first server restart.",
|
||||
"Kiosk health-poll window bumped from 60s to 5 minutes (+TimeoutStartSec=360) so slower hardware doesn't race Chromium against a not-yet-ready backend and white-screen on first boot."
|
||||
"Fixes update.download hard-fail on nodes that have ~/archy checked out (the git-path fleet class: .228, .116). Root cause: handle_update_check's git path returned update_available=true + update_method=\"git\" but never populated state.available_update, so update.download / update.apply RPC calls errored with 'No update available to download' even though the UI advertised one.",
|
||||
"Frontend: SystemUpdate.vue now branches on update_method. When method==\"git\", renders a single 'Pull & Rebuild' action that calls update.git-apply (which runs ~/archy/scripts/self-update.sh: git pull → cargo build --release → frontend rebuild → systemctl restart archipelago). Manifest-path nodes continue to use the existing Download → Apply pipeline. Confirm modal and i18n strings (en + es) added for the git path.",
|
||||
"Forces OTA trigger for nodes already on 1.6.0-alpha (.198, .253) that otherwise saw 'I'm at manifest.version, nothing to do' and skipped the refreshed 1.6 artifacts.",
|
||||
"Container reconciler: scripts/reconcile-containers.sh no longer creates missing containers from the canonical tier spec. SPEC_OPTIONAL now defaults to true in container-specs.sh, so reconcile is strictly a REPAIR tool (fix ownership, restart crashed, recreate on drift). Containers come from exactly two sources: first-boot-containers.sh (baseline filebrowser on unbundled installs) and the package install RPC (every other app). Fixes the bug where fresh unbundled installs woke up 10 minutes after first boot with archy-mempool-db and archy-btcpay-db silently created by the reconcile timer."
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"name": "archipelago",
|
||||
"current_version": "1.5.0-alpha",
|
||||
"new_version": "1.6.0-alpha",
|
||||
"download_url": "https://git.tx1138.com/lfg2025/archy/raw/branch/main/releases/v1.6.0-alpha/archipelago",
|
||||
"sha256": "24fc20d6e76131b44f55e4f41e1355762edf7f6d94b1cbb039fe662e97db41a9",
|
||||
"size_bytes": 40303184
|
||||
"current_version": "1.6.0-alpha",
|
||||
"new_version": "1.7.0-alpha",
|
||||
"download_url": "https://git.tx1138.com/lfg2025/archy/raw/branch/main/releases/v1.7.0-alpha/archipelago",
|
||||
"sha256": "87b945bd6d57825d95b7595409580df5d881cfdbb0f944e00c7c050ecce2a6f3",
|
||||
"size_bytes": 40300680
|
||||
},
|
||||
{
|
||||
"name": "archipelago-frontend-1.6.0-alpha.tar.gz",
|
||||
"current_version": "1.5.0-alpha",
|
||||
"new_version": "1.6.0-alpha",
|
||||
"download_url": "https://git.tx1138.com/lfg2025/archy/raw/branch/main/releases/v1.6.0-alpha/archipelago-frontend-1.6.0-alpha.tar.gz",
|
||||
"sha256": "9118ac5a392c7501d1bf35c8b2c328d00a3b3f0845cb2e5f72fd4337b5687c0c",
|
||||
"size_bytes": 76985839
|
||||
"name": "archipelago-frontend-1.7.0-alpha.tar.gz",
|
||||
"current_version": "1.6.0-alpha",
|
||||
"new_version": "1.7.0-alpha",
|
||||
"download_url": "https://git.tx1138.com/lfg2025/archy/raw/branch/main/releases/v1.7.0-alpha/archipelago-frontend-1.7.0-alpha.tar.gz",
|
||||
"sha256": "cbadd0510362fc9afdc747cba9c70f76315516c2f0f4536044d718aaddcc46fd",
|
||||
"size_bytes": 76982017
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
BIN
releases/v1.7.0-alpha/archipelago
Executable file
BIN
releases/v1.7.0-alpha/archipelago
Executable file
Binary file not shown.
BIN
releases/v1.7.0-alpha/archipelago-frontend-1.7.0-alpha.tar.gz
Normal file
BIN
releases/v1.7.0-alpha/archipelago-frontend-1.7.0-alpha.tar.gz
Normal file
Binary file not shown.
@@ -73,7 +73,12 @@ reset_spec() {
|
||||
SPEC_SECURITY="no-new-privileges:true" SPEC_RESTART="unless-stopped"
|
||||
SPEC_HEALTH_CMD="" SPEC_ENV="" SPEC_CUSTOM_ARGS="" SPEC_READONLY="false"
|
||||
SPEC_TMPFS="" SPEC_TIER="3" SPEC_DATA_DIR="" SPEC_DATA_UID="100000:100000"
|
||||
SPEC_DEPENDS="" SPEC_LOCAL_IMAGE="false" SPEC_OPTIONAL="false"
|
||||
# SPEC_OPTIONAL defaults true: reconcile-containers.sh only REPAIRS existing
|
||||
# containers — it never creates missing ones. Baseline (filebrowser) is
|
||||
# bootstrapped by first-boot-containers.sh; all other apps come from the
|
||||
# install RPC. Per-spec `SPEC_OPTIONAL="true"` lines below are now redundant
|
||||
# but kept for readability.
|
||||
SPEC_DEPENDS="" SPEC_LOCAL_IMAGE="false" SPEC_OPTIONAL="true"
|
||||
SPEC_ENTRYPOINT=""
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user