feat: rootless podman, session hardening, boot stability, sidebar fix

Rootless podman migration (TASK-11):
- Remove sudo from all podman calls in PodmanClient + 8 backend files
- Remove sudo from all podman/docker calls in deploy script
- Restore full systemd security hardening: NoNewPrivileges,
  RestrictAddressFamilies, MemoryDenyWriteExecute, RestrictRealtime,
  RestrictNamespaces, RestrictSUIDSGID, SystemCallFilter, ProtectSystem=strict
- Enable loginctl linger for rootless container persistence
- Remove Ollama from auto-deploy (marketplace-only)

Session & auth hardening:
- Increase MAX_CONCURRENT_SESSIONS 20→50 (prevents eviction storms)
- Debounced 401 redirect in rpc-client.ts (prevents redirect storms)

Boot stability:
- optimize-debian.sh: adds chrony, swap, removes policy-rc.d
- deploy script: pre-restart chrony + swap setup
- ISO build: chrony package, swap file creation
- BootScreen: no longer clears localStorage (prevents splash replay)
- RootRedirect: sole owner of localStorage clearing on server ready

UI fixes:
- Sidebar opacity default changed from 0→visible (fixes missing sidebar
  after page-persistence login without entrance animation)
- Console.log/error wrapped in import.meta.env.DEV guards
- Remove unused route import from RootRedirect

Beta tracking:
- CLAUDE.md: beta freeze protocol added
- MASTER_PLAN.md: TASK-11, TASK-17, phase structure
- BETA-PROGRESS.md: initial tracking doc
- Tagged v1.2.0-alpha.1 as pre-rootless baseline

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-18 13:53:27 +00:00
co-authored by Claude Opus 4.6
parent 934d120243
commit 870ff095d8
48 changed files with 2979 additions and 2196 deletions
+13 -10
View File
@@ -14,12 +14,11 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useRouter } from 'vue-router'
import { isOnboardingComplete } from '@/composables/useOnboarding'
import BootScreen from '@/components/BootScreen.vue'
const router = useRouter()
const route = useRoute()
const showBootScreen = ref(false)
async function quickHealthCheck(): Promise<boolean> {
@@ -66,20 +65,24 @@ async function proceedToApp() {
}
function onServerReady() {
// Clear flags so splash intro plays on reload
if (import.meta.env.DEV) console.log('[RootRedirect] onServerReady — setting flag and reloading')
localStorage.removeItem('neode_intro_seen')
localStorage.removeItem('neode_onboarding_complete')
// Reload with ?intro=1 so we know to skip boot and let App.vue handle splash
window.location.href = '/?intro=1'
sessionStorage.setItem('archipelago_from_boot', '1')
window.location.href = '/'
}
onMounted(async () => {
const devMode = import.meta.env.VITE_DEV_MODE
// Coming back from boot screen — do nothing, let App.vue's SplashScreen take over
if (route.query.intro === '1') {
// Clean the URL without navigating
window.history.replaceState({}, '', '/')
// Coming back from boot screen — let App.vue's SplashScreen take over
if (sessionStorage.getItem('archipelago_from_boot') === '1') {
return
}
// Splash already completed this session — go to app
if (sessionStorage.getItem('archipelago_from_splash') === '1') {
proceedToApp()
return
}
@@ -89,7 +92,7 @@ onMounted(async () => {
return
}
// Boot dev mode — always show boot screen
// Boot dev mode — always show boot screen (first load only)
if (devMode === 'boot') {
showBootScreen.value = true
return