wasm-cli 1.6.0__tar.gz → 1.6.2__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.
- {wasm_cli-1.6.0/src/wasm_cli.egg-info → wasm_cli-1.6.2}/PKG-INFO +1 -1
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/docs/superpowers/plans/2026-08-13-wasm-competitive-parity-roadmap.md +21 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/pyproject.toml +1 -1
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/setup.py +1 -1
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/__init__.py +1 -1
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/env.py +4 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/webapp.py +4 -9
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/base.py +42 -0
- wasm_cli-1.6.2/src/wasm/deployers/helpers/permissions.py +84 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/monorepo.py +21 -31
- {wasm_cli-1.6.0 → wasm_cli-1.6.2/src/wasm_cli.egg-info}/PKG-INFO +1 -1
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm_cli.egg-info/SOURCES.txt +1 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/LICENSE +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/MANIFEST.in +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/README.md +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/docs/MONITOR.md +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/docs/OBS_SETUP.md +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/docs/assets/logo.png +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/docs/assets/logo_bg.png +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/docs/superpowers/specs/2026-08-12-wasm-panel-design-direction.md +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/docs/superpowers/specs/2026-08-12-wasm-v1-refactor-design.md +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/docs/superpowers/specs/2026-08-13-wasm-competitive-parity-design.md +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/docs/superpowers/specs/2026-08-14-wasm-panel-design-v2.md +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/man/wasm.1 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/setup.cfg +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/__main__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/__init__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/app.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/__init__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/backup.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/cert.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/config.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/db.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/health.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/monitor.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/service.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/setup.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/site.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/store.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/version.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/commands/web.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/interactive.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/panel_links.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/cli/prompts.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/completions/README.md +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/completions/_wasm +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/completions/wasm.bash +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/completions/wasm.fish +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/core/__init__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/core/app_state.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/core/config.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/core/dependencies.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/core/exceptions.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/core/fs.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/core/logger.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/core/net.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/core/notifier.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/core/runner.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/core/store.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/core/totp.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/core/update_checker.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/core/utils.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/__init__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/auto.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/docker_compose.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/helpers/__init__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/helpers/env_manager.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/helpers/health.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/helpers/nginx_config.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/helpers/package_manager.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/helpers/path_resolver.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/helpers/preflight.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/helpers/prisma.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/helpers/registration.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/helpers/summary.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/helpers/turbo.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/helpers/workspace.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/interface.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/nextjs.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/nodejs.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/pipeline.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/python.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/recorder.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/registry.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/static.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/deployers/vite.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/main.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/__init__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/apache_manager.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/backup_manager.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/backup_scheduler.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/base_manager.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/cert_manager.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/cron_manager.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/database/__init__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/database/base.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/database/mongodb.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/database/mysql.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/database/postgres.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/database/redis.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/database/registry.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/nginx_manager.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/service_manager.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/source_manager.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/managers/webserver.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/monitor/__init__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/monitor/email_notifier.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/monitor/metrics.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/monitor/models.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/monitor/observation_store.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/monitor/process_monitor.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/monitor/signals.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/monitor/timeseries.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/templates/__init__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/templates/apache/proxy.conf.j2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/templates/apache/static.conf.j2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/templates/nginx/advanced.conf.j2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/templates/nginx/monorepo.conf.j2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/templates/nginx/proxy.conf.j2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/templates/nginx/static.conf.j2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/templates/systemd/_escape.j2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/templates/systemd/app.service.j2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/templates/systemd/backup-service.j2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/templates/systemd/backup-timer.j2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/templates/systemd/cron-service.j2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/templates/systemd/cron-timer.j2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/templates/systemd/docker-compose.service.j2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/validators/__init__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/validators/domain.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/validators/environment.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/validators/names.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/validators/port.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/validators/source.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/validators/ssh.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/__init__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/__init__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/apps.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/auth.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/backup_schedules.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/backups.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/certs.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/config.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/cron.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/databases.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/deps.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/hooks.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/jobs.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/metrics.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/monitor.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/router.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/services.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/sites.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/api/system.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/auth.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/events.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/jobs.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/metrics_collector.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/pydantic_compat.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/server.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/app.css +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/logo.png +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/logo.webp +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/panel.js +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/vendor/fonts/geist-mono-latin-400-normal.woff2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/vendor/fonts/geist-mono-latin-500-normal.woff2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/vendor/fonts/geist-sans-latin-400-normal.woff2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/vendor/fonts/geist-sans-latin-500-normal.woff2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/vendor/fonts/geist-sans-latin-600-normal.woff2 +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/vendor/htmx.min.js +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/vendor/qrcodegen.js +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/vendor/sse.js +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/vendor/uplot.min.css +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/vendor/uplot.min.js +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/vendor/xterm.css +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/static/vendor/xterm.js +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/_macros.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/base.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/api_tokens.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/app_charts.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/app_env.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/backup_schedule_section.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/cron_runs.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/cron_section.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/db_console.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/db_engine.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/deploy_form_check.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/deploy_form_options.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/deploy_recent.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/deploy_rollback.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/deploy_rows.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/infra_service_editor.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/infra_service_form.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/infra_site_editor.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/infra_site_form.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/machine.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/notif_channels.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/sessions.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/settings_editor.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/settings_form_backups.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/settings_form_notifications.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/settings_form_paths.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/settings_form_ssl.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/settings_form_web.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/settings_form_webserver.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/settings_section.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/totp.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/fragments/webhook_section.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/login.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/activity.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/app.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/backups.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/certificates.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/cron.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/dashboard.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/databases.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/deploy.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/deployment_detail.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/deployments.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/failure.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/missing.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/resources.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/service_editor.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/service_new.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/settings.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/site_editor.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/templates/pages/site_new.html +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/views/__init__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/views/app_charts.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/views/backup_schedules.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/views/context.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/views/cron.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/views/databases.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/views/deploy_form.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/views/deployments.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/views/infrastructure.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/views/machine.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/views/rendering.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/views/resources.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/views/router.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/views/settings_editor.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/websockets/__init__.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm/web/websockets/router.py +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm_cli.egg-info/dependency_links.txt +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm_cli.egg-info/entry_points.txt +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm_cli.egg-info/requires.txt +0 -0
- {wasm_cli-1.6.0 → wasm_cli-1.6.2}/src/wasm_cli.egg-info/top_level.txt +0 -0
|
@@ -527,3 +527,24 @@ La API entera ya existe (`api/databases.py`). UI con tabs por engine:
|
|
|
527
527
|
tests con deps de pip NO validan las deps de distro; toda API nueva de una librería
|
|
528
528
|
empaquetada debe contrastarse con la versión de noble/bookworm/Fedora (tabla en
|
|
529
529
|
CLAUDE.md) y el gate del contenedor es el chokepoint que lo garantiza.
|
|
530
|
+
- 2026-08-14 (rediseño): el dueño rechazó la estética austera de la v1 tras usarla
|
|
531
|
+
("pobre, asimétrica, componentes horribles"). Nueva dirección en
|
|
532
|
+
`docs/superpowers/specs/2026-08-14-wasm-panel-design-v2.md` (Geist, acento índigo,
|
|
533
|
+
elevación, esqueleto de página común, pills en vez de raíl) implementada entera y
|
|
534
|
+
**publicada como v1.6.0** (Release y CI verdes). Verificación visual con capturas
|
|
535
|
+
reales (scripts/panel_screenshots.py, 16 pantallas ambos temas + móvil) revisadas
|
|
536
|
+
en dos rondas por el implementador y una por el orquestador. El spec de diseño de
|
|
537
|
+
2026-08-12 queda superado en lo estético; sus restricciones técnicas (CSP, sin
|
|
538
|
+
build, vendor con checksum, color de estado + acento) siguen vigentes.
|
|
539
|
+
- 2026-08-27 (v1.6.1): **EACCES al arrancar toda app no-monorepo**: el deploy corre
|
|
540
|
+
como root y dejaba `/var/www/apps/{app}` propiedad de root mientras la unidad corre
|
|
541
|
+
como `service_user` (www-data); pnpm escribe un temporal `_tmp_*` en el cwd en cada
|
|
542
|
+
`pnpm run`, así que el servicio moría en bucle de reinicios (visto en producción en
|
|
543
|
+
bodas.arennalabs.com). El chown existía solo en el deployer monorepo — regla 3 rota:
|
|
544
|
+
la implementación nunca llegó al pipeline común. Fix en v1.6.1:
|
|
545
|
+
`deployers/helpers/permissions.py::hand_over_tree` como implementación única, paso
|
|
546
|
+
"Setting permissions" en el pipeline base tras el build (afecta a nextjs, nodejs,
|
|
547
|
+
python y vite; static define su propia lista y docker-compose no usa el pipeline —
|
|
548
|
+
a propósito: un `chown -R` sobre bind mounts rompería los datos de contenedores), y
|
|
549
|
+
los `.env` vuelven a 0600 tras el `chmod -R`. Remediación en servidores ya
|
|
550
|
+
desplegados: `chown -R www-data:www-data /var/www/apps/{app}` y restart del unit.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "wasm-cli"
|
|
7
|
-
version = "1.6.
|
|
7
|
+
version = "1.6.2"
|
|
8
8
|
description = "Web App System Management - Deploy and manage web applications on Linux servers"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "WASM-NCSAL" }
|
|
@@ -9,7 +9,7 @@ from setuptools import setup, find_packages
|
|
|
9
9
|
|
|
10
10
|
setup(
|
|
11
11
|
name="wasm-cli",
|
|
12
|
-
version="1.6.
|
|
12
|
+
version="1.6.2",
|
|
13
13
|
description="Web App System Management - Deploy and manage web applications on Linux servers",
|
|
14
14
|
author="Yago López Prado",
|
|
15
15
|
author_email="yago.lopez.adeje@gmail.com",
|
|
@@ -15,7 +15,7 @@ from importlib.metadata import version as _installed_version
|
|
|
15
15
|
#: as an OBS build directory. The single source of truth is the ``version``
|
|
16
16
|
#: field of pyproject.toml; ``scripts/release.py`` keeps this literal and the
|
|
17
17
|
#: distribution packaging files in step with it.
|
|
18
|
-
_FALLBACK_VERSION = "1.6.
|
|
18
|
+
_FALLBACK_VERSION = "1.6.2"
|
|
19
19
|
|
|
20
20
|
try:
|
|
21
21
|
__version__ = _installed_version("wasm-cli")
|
|
@@ -303,6 +303,10 @@ def configure(state: Context, domain: str) -> None:
|
|
|
303
303
|
@click.option(
|
|
304
304
|
"--unmask",
|
|
305
305
|
is_flag=True,
|
|
306
|
+
# Explicit, not implied: click 8.5 reports an unset flag default as a
|
|
307
|
+
# sentinel, and the guarantee that secrets stay masked must not depend on
|
|
308
|
+
# which click a distribution ships.
|
|
309
|
+
default=False,
|
|
306
310
|
help="Print secret values in clear instead of hiding them.",
|
|
307
311
|
)
|
|
308
312
|
@pass_context
|
|
@@ -833,15 +833,10 @@ def _update_monorepo(
|
|
|
833
833
|
deployer.domain = domain
|
|
834
834
|
deployer.package_manager = "pnpm"
|
|
835
835
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
logger.step(
|
|
840
|
-
deployer._run_prisma_migrations()
|
|
841
|
-
|
|
842
|
-
logger.step(6, total_steps, "Building applications")
|
|
843
|
-
deployer._set_permissions()
|
|
844
|
-
deployer._build_all()
|
|
836
|
+
# The deployer's own update, not a copy of its steps: the copy handed the
|
|
837
|
+
# tree over before building and left every build output owned by root.
|
|
838
|
+
step = iter(range(4, total_steps + 1))
|
|
839
|
+
deployer.update(on_step=lambda message: logger.step(next(step), total_steps, message))
|
|
845
840
|
|
|
846
841
|
logger.step(7, total_steps, "Restarting applications")
|
|
847
842
|
service_manager = ServiceManager(verbose=logger.verbose)
|
|
@@ -42,6 +42,7 @@ from wasm.deployers.helpers import (
|
|
|
42
42
|
)
|
|
43
43
|
from wasm.deployers.helpers.health import failure_output, wait_until_healthy
|
|
44
44
|
from wasm.deployers.helpers.nginx_config import NginxAdvancedConfig
|
|
45
|
+
from wasm.deployers.helpers.permissions import hand_over_tree
|
|
45
46
|
from wasm.deployers.helpers.registration import StoreRegistrar
|
|
46
47
|
from wasm.deployers.helpers.summary import print_deployment_summary
|
|
47
48
|
from wasm.deployers.interface import AppDeployer, StepReporter, UpdateResult
|
|
@@ -1163,6 +1164,11 @@ class BaseDeployer(AppDeployer):
|
|
|
1163
1164
|
icon=Icons.BUILD,
|
|
1164
1165
|
run=self.build,
|
|
1165
1166
|
),
|
|
1167
|
+
DeployStep(
|
|
1168
|
+
title="Setting permissions",
|
|
1169
|
+
icon=Icons.LOCK,
|
|
1170
|
+
run=self._set_permissions,
|
|
1171
|
+
),
|
|
1166
1172
|
DeployStep(
|
|
1167
1173
|
title="Creating site configuration",
|
|
1168
1174
|
icon=Icons.GLOBE,
|
|
@@ -1235,6 +1241,36 @@ class BaseDeployer(AppDeployer):
|
|
|
1235
1241
|
if self.app_name:
|
|
1236
1242
|
self.store.update_service_status(self.app_name, active=True, enabled=True)
|
|
1237
1243
|
|
|
1244
|
+
def _set_permissions(self) -> None:
|
|
1245
|
+
"""
|
|
1246
|
+
Hand the deployed tree over to the account the service runs as.
|
|
1247
|
+
|
|
1248
|
+
The deployment ran as root, so without this step the service user
|
|
1249
|
+
cannot write into its own app directory and the unit fails at start
|
|
1250
|
+
with EACCES.
|
|
1251
|
+
"""
|
|
1252
|
+
hand_over_tree(
|
|
1253
|
+
self.app_path,
|
|
1254
|
+
user=self.config.service_user,
|
|
1255
|
+
group=self.config.service_group,
|
|
1256
|
+
runner=self.runner,
|
|
1257
|
+
fs=self.fs,
|
|
1258
|
+
logger=self.logger,
|
|
1259
|
+
env_files=self._env_files(),
|
|
1260
|
+
)
|
|
1261
|
+
|
|
1262
|
+
def _env_files(self) -> list[Path]:
|
|
1263
|
+
"""
|
|
1264
|
+
List the environment files whose modes must survive ``_set_permissions``.
|
|
1265
|
+
|
|
1266
|
+
Returns:
|
|
1267
|
+
The dotenv files at the application root. Subclasses that write
|
|
1268
|
+
environment files elsewhere override this.
|
|
1269
|
+
"""
|
|
1270
|
+
if not self.app_path.is_dir():
|
|
1271
|
+
return []
|
|
1272
|
+
return sorted(path for path in self.app_path.glob(".env*") if path.is_file())
|
|
1273
|
+
|
|
1238
1274
|
def _recorder(self) -> DeploymentRecorder:
|
|
1239
1275
|
"""
|
|
1240
1276
|
Build the recorder :meth:`deploy` and :meth:`update` write history with.
|
|
@@ -1312,6 +1348,12 @@ class BaseDeployer(AppDeployer):
|
|
|
1312
1348
|
report("Building")
|
|
1313
1349
|
self.build()
|
|
1314
1350
|
|
|
1351
|
+
# The pull, the install and the build all ran as root, and the
|
|
1352
|
+
# service writes into what they produced: Next.js creates
|
|
1353
|
+
# .next/cache/images on the first optimised image, and uploads land
|
|
1354
|
+
# in directories a pull may have just added.
|
|
1355
|
+
self._set_permissions()
|
|
1356
|
+
|
|
1315
1357
|
start_command = self.get_start_command()
|
|
1316
1358
|
result = UpdateResult(
|
|
1317
1359
|
package_manager=self.package_manager,
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026 Yago Lopez Prado
|
|
2
|
+
# Licensed under WASM-NCSAL 1.0 (Commercial use prohibited)
|
|
3
|
+
# https://github.com/Perkybeet/wasm/blob/main/LICENSE
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Ownership hand-over for deployed trees.
|
|
7
|
+
|
|
8
|
+
The whole deployment runs as root, but the generated unit runs as the
|
|
9
|
+
configured service user. That user must be able to write into the app
|
|
10
|
+
directory: pnpm creates a temporary file in the project root on every
|
|
11
|
+
``pnpm run``, and Next.js writes into ``.next`` at runtime, so a root-owned
|
|
12
|
+
tree fails at start with EACCES and systemd restarts it forever.
|
|
13
|
+
|
|
14
|
+
This is the one implementation both the base pipeline and the monorepo
|
|
15
|
+
deployer use; it used to exist only in the monorepo deployer, which is why
|
|
16
|
+
every other app type shipped with the bug above.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from collections.abc import Iterable
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
from wasm.core.fs import SECRET_MODE, FileSystem
|
|
25
|
+
from wasm.core.logger import Logger
|
|
26
|
+
from wasm.core.runner import CommandRunner
|
|
27
|
+
|
|
28
|
+
#: Deadline for the recursive chown and chmod over a deployed tree.
|
|
29
|
+
_PERMISSIONS_TIMEOUT = 60
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def hand_over_tree(
|
|
33
|
+
app_path: Path,
|
|
34
|
+
*,
|
|
35
|
+
user: str,
|
|
36
|
+
group: str,
|
|
37
|
+
runner: CommandRunner,
|
|
38
|
+
fs: FileSystem,
|
|
39
|
+
logger: Logger,
|
|
40
|
+
env_files: Iterable[Path] = (),
|
|
41
|
+
) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Make ``user`` the owner of the deployed tree, keeping secrets private.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
app_path: Root of the deployed application.
|
|
47
|
+
user: Account the service runs as.
|
|
48
|
+
group: Group the service runs as.
|
|
49
|
+
runner: Runner the chown and chmod execute through.
|
|
50
|
+
fs: Filesystem used to restore the mode of the secret files.
|
|
51
|
+
logger: Logger for the non-fatal failures.
|
|
52
|
+
env_files: Files holding secrets whose mode must come back to 0600
|
|
53
|
+
after the recursive chmod.
|
|
54
|
+
"""
|
|
55
|
+
result = runner.run(
|
|
56
|
+
["chown", "-R", f"{user}:{group}", str(app_path)],
|
|
57
|
+
timeout=_PERMISSIONS_TIMEOUT,
|
|
58
|
+
)
|
|
59
|
+
# Not fatal: the build is good, and an app that never writes runs fine. One
|
|
60
|
+
# that does fails with EACCES in its own log, far from here, so this is the
|
|
61
|
+
# only place the operator can be told the cause.
|
|
62
|
+
if not result.success:
|
|
63
|
+
logger.warning(
|
|
64
|
+
f"Could not hand {app_path} over to {user}:{group}; the service may fail "
|
|
65
|
+
f"with EACCES: {result.stderr.strip()}"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Directories need the execute bit and the built assets must stay readable
|
|
69
|
+
# by the web server, whatever umask the fetch and the build left behind.
|
|
70
|
+
result = runner.run(
|
|
71
|
+
["chmod", "-R", "u+rwX,g+rX,o+rX", str(app_path)],
|
|
72
|
+
timeout=_PERMISSIONS_TIMEOUT,
|
|
73
|
+
)
|
|
74
|
+
if not result.success:
|
|
75
|
+
logger.warning(
|
|
76
|
+
f"Could not make {app_path} readable by the web server: {result.stderr.strip()}"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# That -R also put o+r on the .env files, which hold the secrets this
|
|
80
|
+
# deployment was given. The chown above has just made the service account
|
|
81
|
+
# their owner, so 0600 is readable by the application and by nobody else.
|
|
82
|
+
for env_file in env_files:
|
|
83
|
+
if env_file.exists():
|
|
84
|
+
fs.chmod(env_file, SECRET_MODE)
|
|
@@ -49,6 +49,7 @@ from wasm.deployers.helpers import (
|
|
|
49
49
|
TurboHelper,
|
|
50
50
|
WorkspaceHelper,
|
|
51
51
|
)
|
|
52
|
+
from wasm.deployers.helpers.permissions import hand_over_tree
|
|
52
53
|
from wasm.deployers.interface import AppDeployer, StepReporter, UpdateResult
|
|
53
54
|
from wasm.deployers.registry import DeployerRegistry
|
|
54
55
|
from wasm.managers.apache_manager import ApacheManager
|
|
@@ -415,9 +416,6 @@ class MonorepoDeployer(AppDeployer):
|
|
|
415
416
|
self.logger.step(5, total_steps, "Installing dependencies", Icons.PACKAGE)
|
|
416
417
|
self._install_dependencies()
|
|
417
418
|
|
|
418
|
-
# Set permissions for service user
|
|
419
|
-
self._set_permissions()
|
|
420
|
-
|
|
421
419
|
# Step 6: Prisma migrations
|
|
422
420
|
self.logger.step(6, total_steps, "Running database migrations", Icons.DATABASE)
|
|
423
421
|
self._run_prisma_migrations()
|
|
@@ -426,6 +424,10 @@ class MonorepoDeployer(AppDeployer):
|
|
|
426
424
|
self.logger.step(7, total_steps, "Building applications", Icons.BUILD)
|
|
427
425
|
self._build_all()
|
|
428
426
|
|
|
427
|
+
# Only now: the build runs as root too, and handing over before it
|
|
428
|
+
# left every workspace's build output unwritable by its service.
|
|
429
|
+
self._set_permissions()
|
|
430
|
+
|
|
429
431
|
# Step 8: Create sites (without SSL initially)
|
|
430
432
|
self.logger.step(8, total_steps, "Creating site configurations", Icons.GLOBE)
|
|
431
433
|
self._create_sites(with_ssl=False)
|
|
@@ -533,8 +535,8 @@ class MonorepoDeployer(AppDeployer):
|
|
|
533
535
|
prisma_updated = self._run_prisma_migrations()
|
|
534
536
|
|
|
535
537
|
report("Building applications")
|
|
536
|
-
self._set_permissions()
|
|
537
538
|
self._build_all()
|
|
539
|
+
self._set_permissions()
|
|
538
540
|
|
|
539
541
|
return UpdateResult(
|
|
540
542
|
package_manager=self.package_manager,
|
|
@@ -948,34 +950,22 @@ class MonorepoDeployer(AppDeployer):
|
|
|
948
950
|
return False
|
|
949
951
|
|
|
950
952
|
def _set_permissions(self) -> None:
|
|
951
|
-
"""
|
|
952
|
-
|
|
953
|
-
service_group = self.config.service_group
|
|
954
|
-
|
|
955
|
-
try:
|
|
956
|
-
# Change ownership recursively
|
|
957
|
-
result = self.runner.run(
|
|
958
|
-
["chown", "-R", f"{service_user}:{service_group}", str(self.app_path)],
|
|
959
|
-
timeout=60,
|
|
960
|
-
)
|
|
961
|
-
if not result.success:
|
|
962
|
-
self.logger.debug(f"chown failed: {result.stderr}")
|
|
953
|
+
"""
|
|
954
|
+
Hand the deployed tree over to the account the services run as.
|
|
963
955
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
self.
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
if env_file.exists():
|
|
978
|
-
self.fs.chmod(env_file, SECRET_MODE)
|
|
956
|
+
The deployment ran as root, so without this step the workspace units
|
|
957
|
+
cannot write into their own app directory and fail at start with
|
|
958
|
+
EACCES.
|
|
959
|
+
"""
|
|
960
|
+
hand_over_tree(
|
|
961
|
+
self.app_path,
|
|
962
|
+
user=self.config.service_user,
|
|
963
|
+
group=self.config.service_group,
|
|
964
|
+
runner=self.runner,
|
|
965
|
+
fs=self.fs,
|
|
966
|
+
logger=self.logger,
|
|
967
|
+
env_files=self._env_files(),
|
|
968
|
+
)
|
|
979
969
|
|
|
980
970
|
def _env_files(self) -> list[Path]:
|
|
981
971
|
"""
|
|
@@ -74,6 +74,7 @@ src/wasm/deployers/helpers/health.py
|
|
|
74
74
|
src/wasm/deployers/helpers/nginx_config.py
|
|
75
75
|
src/wasm/deployers/helpers/package_manager.py
|
|
76
76
|
src/wasm/deployers/helpers/path_resolver.py
|
|
77
|
+
src/wasm/deployers/helpers/permissions.py
|
|
77
78
|
src/wasm/deployers/helpers/preflight.py
|
|
78
79
|
src/wasm/deployers/helpers/prisma.py
|
|
79
80
|
src/wasm/deployers/helpers/registration.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wasm_cli-1.6.0 → wasm_cli-1.6.2}/docs/superpowers/specs/2026-08-12-wasm-panel-design-direction.md
RENAMED
|
File without changes
|
{wasm_cli-1.6.0 → wasm_cli-1.6.2}/docs/superpowers/specs/2026-08-12-wasm-v1-refactor-design.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|