Conversation
added 30 commits
December 20, 2025 16:50
- Replace requirements.txt with pyproject.toml in all Docker images - Install uv in Dockerfiles before installing Python dependencies - Use 'uv pip install --system' instead of 'pip install'
Coverage configuration enables automatic code coverage collection across all Docker containers during test runs. Includes sitecustomize.py that starts coverage when COVERAGE_PROCESS_START is set. - Add coverage volume and environment variables to docker-compose - Install coverage package in all Dockerfiles - Copy sitecustomize.py for automatic coverage collection - Propagate coverage environment to student containers - Add shutdown delay for coverage data flush
Uses bridge_id template variable to create unique network bridge names during test runs, preventing conflicts when running multiple test instances in parallel.
Introduces a separate config_test.py with TestConfig class for running unit tests outside the container environment. Uses descriptors to raise RuntimeError when infrastructure-dependent config values are accessed, helping identify code paths incompatible with standalone testing.
SFTP and non-interactive SSH sessions require a clean stdout channel for protocol data. This change ensures the wrapper does not pollute stdout with messages that would break these sessions. - Redirect print_ok/warn/err functions to stderr - Only print banner and welcome messages for interactive sessions - Check sys.stdout.isatty() before printing user-facing messages
Introduces ref.core.logging with get_logger() that works both inside Flask application context and in standalone environments. Replaces direct LocalProxy(lambda: current_app.logger) usage across modules, enabling unit testing without Flask being available.
- Use psycopg2-binary instead of psycopg2 for easier installation - Add version to setup.py
Unit tests for error handling, exercise config parsing, security module, SSH client, web client, and utility functions.
Run linting (ruff, pyright, mypy), unit tests, and E2E tests. Upload coverage reports and failure logs as artifacts.
Load submission_tests as a Python module instead of running it as a subprocess. This allows direct use of the run_tests() function from ref_utils, eliminating the need for JSON file-based result passing. Changes: - submission_tests: Use @environment_test and @submission_test decorators - task.py: Import and call run_tests() directly, capture output via TeeWriter
The create_submission method expects List[SubmissionTestResult] but was being called with (int, str) arguments. Create a proper SubmissionTestResult object with task_name='manual' for admin-created submissions. Fixes #28
Replace generic message with actionable guidance explaining that users should remove debug prints or reduce unnecessary output to stay within the allowed limit. Fixes #27
Generate a 6-character alphanumeric ID on first startup and store it in the database. This ID is included in all Docker resource names (containers, networks, images) to distinguish resources created by different REF installations. Resource naming changes from: ref-ressource-exercise-v1-entry-42 to: ref-a1b2c3-exercise-v1-entry-42 This enables detection and cleanup of orphan resources from old or reset installations. Closes #24
Add tee command to save build output to tests/build_logs/docker-build.log and upload it as an artifact for debugging failed builds.
Initialize only the submodules required for testing (openssh-portable, ref-utils, ace-builds) instead of cloning all submodules recursively. Add REF_CI_RUN environment variable to skip cgroup freezer, cgroup version checks, and ref-linux submodule requirement in CI.
- Remove unused imports and variables - Replace bare `except:` clauses with `except Exception:` - Replace lambda assignments with def statements (E731) - Fix ambiguous variable names (l -> link, etc.) - Add TYPE_CHECKING imports for forward references - Use explicit re-export syntax for module __init__.py files - Add noqa comments for SQLAlchemy comparisons (== None/True)
Add hooks/pre-commit that runs ruff check and ruff format --check, rejecting commits that fail. Include hooks/install.sh for easy setup.
Run the full CI lint suite: ruff check, ruff format, pyright, and mypy.
- Add mypy config to tests/pyproject.toml with strict settings - Add pyright config options for missing imports and lambda types - Add type annotations to test fixture parameters in test_util.py - Fix formatting in webapp/ref/model/exercise.py
Replace pyright with mypy as the sole type checker. Update documentation, CI workflow, and pre-commit hook to use only ruff and mypy.
The hook ensures main is always an ancestor of dev, so rebasing dev onto main never requires a merge commit.
added 26 commits
April 13, 2026 12:59
Extract administrative fields (category, deadlines, grading points, submission test toggle) from Exercise into a new ExerciseConfig model. All versions of an exercise share one ExerciseConfig row via config_id FK. Exercise proxies the moved fields as properties for full backwards compatibility. Add web UI for editing ExerciseConfig (category, deadlines, grading, short name rename) with date pickers. Add scoring_policy JSON column for future scoreboard integration. Deprecate admin fields in exercise YAML configs with inline warnings in the importable list. Add graceful handling for pending migrations on startup.
Rewrite prepare.py as a first-run initializer that generates settings.yaml with cryptographically secure random secrets (ADMIN_PASSWORD, SECRET_KEY, SSH_TO_WEB_KEY, POSTGRES_PASSWORD) using Python's secrets module, auto-detects DOCKER_GROUP_ID, and renders settings.env from settings.yaml so docker-compose keeps working unchanged. Refuses to run when settings.yaml already exists so existing secrets are never silently overwritten. ctrl.sh now bootstraps configuration by invoking prepare.py automatically on the first run (when no settings files are present) and otherwise verifies that all generated artifacts exist. settings.yaml is added to .gitignore so the plaintext secrets cannot be committed by accident. README and template.env are updated to point at the new flow. Closes #11
…rading Adds a GroupNameList model for admin-curated name pools, a System -> Group Names page to manage them, and two system settings (GROUPS_ENABLED, GROUP_SIZE) that gate the feature. When enabled, student registration offers a datalist of names from enabled lists with current occupancy (n/k), creating or joining a UserGroup under a row lock with a capacity check. Admins can also assign users to groups from the edit page, including names from enabled lists. Grading switches to one submission per group via Exercise.submission_heads_by_group[_global](), falling back to per-user behavior for ungrouped users. Seeds Raid and Fuzzing name lists (32 each) via an Alembic migration. Refs #14
The build thread detaches the Exercise plus its forward relationships so attribute access during the long-running Docker build does not trigger a lazy load that would reopen a transaction and hold the build advisory lock. Extends that pattern to the config relationship added with ExerciseConfig, otherwise touching exercise.config in __run_build raises DetachedInstanceError.
Introduce a public scoreboard ported from the raid/raid prototype, rebuilt on the current dev codebase as two independent extension points: - Scoring policy per ExerciseConfig — linear (with configurable raw bounds), threshold, or tiered — applied server-side when the submissions API serves transformed scores. - Ranking strategy — f1_time_weighted (Formula 1 time-weighted points) or best_sum (sum of each team's best per challenge). Selected at runtime via SCOREBOARD_RANKING_MODE; adding a third strategy is one JS module plus one entry in ref/core/scoring.py. - Visual view — default (retro-terminal dark theme with Chart.js highscore panels, ranking table, points-over-time chart, per-challenge plots, live countdowns) or minimal (Bootstrap ranking table). Selected via SCOREBOARD_VIEW; adding a third view is one template plus one entry module. Only assignments whose exercises are actually online (a built default Exercise row exists) are exposed by /api/scoreboard/config. The default view auto-selects the assignment whose submission window is currently open, and preserves user assignment/challenge tab selections across the 5-second auto-refresh polls. Team identity is group-aware: ranking rows show the UserGroup name when GROUPS_ENABLED, otherwise the student's full name. Site-wide navigation is unified via a new _navbar.html partial included from student_base.html and admin_base.html, with Registration / Restore Key / Scoreboard entries always visible and Admin / Grading / System dropdowns gated on the user's authorization. Adds a landing chooser page (SCOREBOARD_LANDING_PAGE = "chooser") that shows the registration/restore buttons plus a live ranking preview. Closes #12 Closes #13 Closes #15
Install ref-utils at /opt/ref-utils with `uv pip install -e .` and bind-mount the host source read-only over it from the webapp so edits apply inside instance containers without rebuilding the base image.
Document view/model/core module layouts, container tooling, ref-utils exports, Docker network bridge names, ctrl.sh subcommands, test directory structure, and CI pipeline.
The forked PySocks package was only used by the Python SSH proxy in webapp/ref/proxy/, which was removed when the Rust SSH reverse proxy replaced it.
…emand
prepare.py now has two modes: bootstrap (no settings.yaml) generates fresh
secrets as before, and re-render (settings.yaml exists) loads the existing
yaml and re-propagates it into settings.env and docker-compose.yml without
touching the secrets. Routine config edits are now "edit settings.yaml,
re-run ./prepare.py, ./ctrl.sh restart" instead of hand-syncing two files.
Pass --fresh to force regeneration; the existing yaml is moved to
settings.yaml.backup first.
Lift data_path, exercises_path, ref_utils_path, and binfmt_support from
hard-coded values in prepare.py into new paths and runtime sections of
settings.yaml, and parameterize the ref-utils bind-mount source in the
compose template via {{ ref_utils_path }}. load_settings_yaml backfills
these sections into older yamls and always re-emits the file so the
current schema, key order, and section comments propagate automatically.
The test harness passes an absolute ref_utils_path so its generated
compose still renders correctly.
Drop the dead debug / maintenance_enabled fields from settings.yaml and
settings.env — they were always overridden by ctrl.sh up's shell exports.
The compose template now uses ${DEBUG:-0} / ${MAINTENANCE_ENABLED:-0}
defaults so non-up commands (build, restart, logs) no longer need the
values in settings.env.
settings.yaml and settings.env are now self-documenting: each top-level
yaml section carries a preamble comment explaining its purpose, and each
env var gets a descriptive comment above it. docs/CONFIG.md documents the
full configuration pipeline: the three-file data flow, bootstrap vs
re-render, the yaml schema, secret rotation, test-harness divergence, and
the remaining gotchas. template.env (a redirect stub) and the obsolete
settings.env.backup gitignore entry are removed.
- Replace 'wave' with 'assignment' in SCOREBOARD.md and in comments
and user-facing strings under webapp/ref/{view/api.py, core/scoring.py,
model/exercise_config.py}.
- Add an "Optional Features" section to README.md describing the groups
and scoreboard settings, both disabled by default and configured from
the admin system-settings page.
- Move JSON endpoints out of `view/api.py` into `services_api/` (SSH proxy + container callbacks) and `frontend_api/` (SPA `/api/v2/*` + scoreboard). `view/build_status.py` hosts the admin build-status poll. - Delete Flask-rendered registration, restore-key, scoreboard, and chooser landing pages along with their templates, static JS/CSS, and vendored chart assets; the SPA serves these under `/v2/*`. - Drop `SCOREBOARD_VIEW` setting and the view resolver — only one scoreboard renderer exists. - Redirect `/`, `/student`, and `/student/` straight to the configured SPA landing page; admin navbar drops its public student links. - Rework the Vue scoreboard charts to plot only per-team improvements, use distinct marker shapes, and support drag-pan / wheel-zoom / shift-drag box-zoom via `chartjs-plugin-zoom`; clamp the x-axis at the earliest data point and preserve zoom state across data polls. - Refresh `ARCHITECTURE.md`, `SCOREBOARD.md`, `CLAUDE.md`, and `README.md` to describe the current package layout.
Vue 3 + Vite + Vuetify app served under `/v2/`. Hosts the public scoreboard, student registration, and key-restore flows backed by `ref/frontend_api/`. Ships the ranking strategies, scoreboard components, routing, theme tokens, and the Dockerfile/entrypoint used by the `ref-spa-frontend` service.
- Add a `spa-frontend` service to the compose template that bind-mounts the host sources and toggles between `vite dev` and `vite preview` via `HOT_RELOADING`. - Publish the container port through `SPA_HOST_PORT` (default 5173) and teach `prepare.py` to render it into `settings.env`. - Extend `--hot-reloading` help in `ctrl.sh` to mention the SPA Vite HMR. - Ignore `spa-frontend/node_modules/` and `spa-frontend/dist/`.
setuptools regenerates this directory on every install, so keeping it in the tree just produces spurious diffs whenever `pyproject.toml` changes.
ExerciseConfig now carries a per_task_scoring_policies JSON column keyed by submission-test task name instead of a single scoring_policy dict. Task names are AST-discovered from each exercise's submission_tests file, so the config editor shows exactly the tasks registered by the test script. Submissions are scored with score_submission(), which applies each task's policy independently and returns (total, per-task breakdown); the scoreboard API exposes the breakdown to the SPA. The public scoreboard drops the user-selectable ranking strategy: the SCOREBOARD_RANKING_MODE setting and RANKING_STRATEGIES registry are removed, and the SPA is hardwired to the best-sum strategy. The chart samples the timeline at real event timestamps only, so every plotted point corresponds to an actual submission or window edge.
- Swap chart.js, chartjs-adapter-date-fns, chartjs-plugin-annotation, and chartjs-plugin-zoom for echarts v6 in the SPA dependencies. - Reimplement PointsOverTimeChart and ChallengePlot against the echarts API (line charts, markLine boundaries, built-in dataZoom slider). - Read axis, grid, legend, tooltip, slider, and data palette colors from Vuetify --v-theme-* tokens and re-render via a MutationObserver when the body theme class flips. - Give .term-chart-wrap an explicit height and use a flex child so the chart container reports a non-zero size to echarts.init(). - Extend the x-axis range to include assignment boundary markers so the dashed guide lines stay inside the viewport. - Rotate assignment labels 90 degrees and center them along each vertical boundary line; center the baseline label on the horizontal markLine.
best_sum.computeChartScoresOverTime() used to inject a synthetic
{time: now, score: 0} point for any team present in the submission
map but without any events inside an assignment window. That placeholder
rendered as a stray zero data point in the chart. Omit such teams from
the result instead.
Also refresh docs/SCOREBOARD.md to describe the current ECharts-based
rendering, the theme-token color wiring, the assignment-boundary label
layout, and the x-axis range expansion that keeps boundary markers in
the viewport.
Tooltip and x-axis labels in the points-over-time and challenge plots now use Intl.DateTimeFormat with the user's locale. The points-over-time chart only renders assignment boundary markers for assignments whose start date has already passed. Also fix pre-existing typecheck errors in the ECharts series/markLine options and resolve a type-identity conflict between the 'echarts' and 'echarts/core' module declarations.
Adds a new frontend-proxy service (multi-stage Dockerfile: node builder
stage compiles the SPA bundle; caddy:2-alpine runtime stage serves it)
that terminates the host HTTP port and fans out over the existing
web-host network:
/spa/* -> spa-frontend:5173 (vite dev) in dev, baked /srv/spa-dist
via file_server in prod
/static/* -> webapp/ref/static bind-mount served directly by Caddy
/admin, /admin/ -> 302 to /admin/exercise/view
/spa -> 308 /spa/
everything else -> reverse_proxy web:8000 (X-Tinyproxy set from
remote_host so the rate limiter keys on real client IP)
Dev/prod Caddyfiles are selected at container start via entrypoint.sh
based on $HOT_RELOADING. Prod adds Cache-Control headers: immutable +
long max-age on /spa/assets/*, no-cache on the SPA HTML fallback, 1h on
Flask static assets. Caddy's reverse_proxy auto-upgrades Vite's HMR
websocket for /spa/@vite/client.
The SPA URL prefix moves from /v2 to /spa (vite base, router history,
Flask landing redirects). The /api/v2/* JSON API path is unchanged.
The spa-frontend service is gated behind the 'dev' compose profile so
it only starts when hot-reloading is active; ctrl.sh exports
COMPOSE_PROFILES=dev by default and clears it in prod-mode up. The
prod-mode branch of spa-frontend/entrypoint.sh is now a hard error
since the prod bundle is baked into the frontend-proxy image.
web and spa-frontend no longer publish host ports; the test harness
maps frontend-proxy:8000 instead. SPA_HOST_PORT is removed from
settings.yaml/env and prepare.py. A repo-root .dockerignore keeps the
frontend-proxy build context lean.
UI:
- SPA DefaultLayout app bar gets an unobtrusive mdi-shield-account-outline
icon button linking to /admin.
- Admin navbar gains a "Student View" link (school icon + label) with a
pipe separator from the user name/logout group.
- Admin navbar brand (logo + course name) now links to the exercise view
instead of the SPA landing.
SPA:
- DefaultLayout renders a yellow/black hazard-striped v-system-bar at
the top of every page when import.meta.env.DEV is true, with the
text "Served by vite dev with HMR — do not expose this instance
publicly." The whole block is tree-shaken out of the production
vite build.
- App.vue sets document.title from the nav store's courseName
("REF - <course>"), falling back to plain "REF" until hydrate
finishes or if the API call fails.
Docs:
- README gains "Single-port web interface" and "Hot reloading (local
development only)" sections spelling out that --hot-reloading runs
vite dev behind Caddy and must never be used on a publicly
reachable host, and that SPA source changes require ./ctrl.sh build
in prod mode since the bundle is baked into the frontend-proxy
image.
- docs/ARCHITECTURE.md adds /admin and /spa redirect notes, a
Dev-mode security warning block covering the vite dev attack
surface, a note on ctrl.sh's COMPOSE_PROFILES=dev wiring, and a
warning box next to the --hot-reloading command reference.
- .claude/CLAUDE.md splits the web description into separate entries
for the Flask webapp (internal port only) and the Caddy
frontend-proxy, with the full routing table, profile gate, and
security warning.
Registration generates ed25519 pairs but the Content-Disposition on the student key downloads and the `download` attributes in KeyDownloadCard were hardcoded to `id_rsa`, so users saved ed25519 keys under an RSA filename. Add `ssh_key_basename()` in `ref.core.util` and a TS twin in the SPA to pick the name ssh-keygen would default to (id_ed25519 / id_ecdsa / id_rsa / id_dsa), and route both download endpoints and the card through it. Also switch admin bootstrap to ed25519 so a freshly seeded admin user matches the rest of the system.
Fix typos, clarify service descriptions (frontend-proxy routing, SSH reverse proxy naming), and remove outdated wording.
The frontend-proxy (Caddy) now supports three TLS modes controlled by tls.mode in settings.yaml: - off: plain HTTP on a single port (previous behavior) - internal: self-signed certificate with HTTPS + plain HTTP side-by-side - acme: Let's Encrypt certificate via ACME with automatic renewal The Caddyfile is rendered at container start from a Jinja2 template (Caddyfile.prod.j2) by render_caddyfile.py based on environment variables. Shared routing directives live in Caddyfile.routes, imported by all prod configurations. New settings: tls.mode, tls.domain (required when TLS is enabled), tls.redirect_http_to_https, and ports.https_host_port. New installs default to internal mode on ports 8080/8443. Existing configs are backfilled to off mode preserving current port assignments. A caddy-data Docker volume persists certificate state across restarts.
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 23606779 | Triggered | OpenSSH Private Key | fa33740 | container-keys/user_key | View secret |
| 23606780 | Triggered | OpenSSH Private Key | fa33740 | container-keys/root_key | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secrets safely. Learn here the best practices.
- Revoke and rotate these secrets.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
Comment on lines
+14
to
+49
| name: Lint & Type Check | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Initialize submodules (excluding ref-linux) | ||
| run: | | ||
| git submodule update --init ref-docker-base/ref-utils | ||
| git submodule update --init webapp/ref/static/ace-builds | ||
|
|
||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v4 | ||
|
|
||
| - name: Set up Python | ||
| run: uv python install ${{ env.PYTHON_VERSION }} | ||
|
|
||
| - name: Install linting tools | ||
| run: | | ||
| uv tool install ruff | ||
| uv tool install mypy | ||
|
|
||
| - name: Install test dependencies (for mypy) | ||
| working-directory: tests | ||
| run: uv sync | ||
|
|
||
| - name: Run ruff check | ||
| run: ruff check . | ||
|
|
||
| - name: Run ruff format check | ||
| run: ruff format --check . | ||
|
|
||
| - name: Run mypy | ||
| working-directory: tests | ||
| run: uv run mypy . | ||
|
|
||
| unit-tests: |
Comment on lines
+50
to
+74
| name: Unit Tests | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Initialize submodules (excluding ref-linux) | ||
| run: | | ||
| git submodule update --init ref-docker-base/ref-utils | ||
| git submodule update --init webapp/ref/static/ace-builds | ||
|
|
||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v4 | ||
|
|
||
| - name: Set up Python | ||
| run: uv python install ${{ env.PYTHON_VERSION }} | ||
|
|
||
| - name: Install test dependencies | ||
| working-directory: tests | ||
| run: uv sync | ||
|
|
||
| - name: Run unit tests | ||
| working-directory: tests | ||
| run: uv run pytest unit/ -v -m "not slow" | ||
|
|
||
| e2e-tests: |
Comment on lines
+75
to
+188
| name: E2E Tests | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 30 | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Initialize submodules (excluding ref-linux) | ||
| run: | | ||
| git submodule update --init ref-docker-base/ref-utils | ||
| git submodule update --init webapp/ref/static/ace-builds | ||
|
|
||
| - name: Install system dependencies | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y jq | ||
|
|
||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v4 | ||
|
|
||
| - name: Set up Python | ||
| run: uv python install ${{ env.PYTHON_VERSION }} | ||
|
|
||
| - name: Install Python dependencies for ctrl.sh | ||
| run: pip install jinja2 | ||
|
|
||
| - name: Create settings.env | ||
| run: | | ||
| DOCKER_GID=$(getent group docker | cut -d: -f3) | ||
| cat > settings.env << EOF | ||
| DEBUG=1 | ||
| MAINTENANCE_ENABLED=0 | ||
| ADMIN_PASSWORD=TestAdmin123! | ||
| DOCKER_GROUP_ID=${DOCKER_GID} | ||
| SSH_HOST_PORT=2222 | ||
| HTTP_HOST_PORT=8000 | ||
| SECRET_KEY=TestSecretKeyForCI12345 | ||
| SSH_TO_WEB_KEY=TestSSHToWebKeyForCI | ||
| POSTGRES_PASSWORD=TestPostgresPassword123! | ||
| EOF | ||
| # Remove leading whitespace from each line | ||
| sed -i 's/^[[:space:]]*//' settings.env | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v3 | ||
|
|
||
| - name: Cache Docker layers | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: /tmp/.buildx-cache | ||
| key: ${{ runner.os }}-buildx-${{ github.sha }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-buildx- | ||
|
|
||
| - name: Build Docker images | ||
| run: | | ||
| mkdir -p tests/build_logs | ||
| export REF_CI_RUN=1 | ||
| ./ctrl.sh build 2>&1 | tee tests/build_logs/docker-build.log | ||
| exit ${PIPESTATUS[0]} | ||
|
|
||
| - name: Install test dependencies | ||
| working-directory: tests | ||
| run: uv sync | ||
|
|
||
| - name: Run E2E tests | ||
| working-directory: tests | ||
| run: uv run pytest e2e/ -v --timeout=300 | ||
|
|
||
| - name: Upload coverage report | ||
| uses: actions/upload-artifact@v4 | ||
| if: always() | ||
| with: | ||
| name: coverage-report | ||
| path: tests/coverage_reports/ | ||
| retention-days: 7 | ||
|
|
||
| - name: Generate failure log summary | ||
| if: failure() | ||
| working-directory: tests | ||
| run: | | ||
| if [ -d "failure_logs" ]; then | ||
| uv run python summarize_logs.py || true | ||
| fi | ||
|
|
||
| - name: Upload failure logs | ||
| uses: actions/upload-artifact@v4 | ||
| if: failure() | ||
| with: | ||
| name: failure-logs | ||
| path: tests/failure_logs/ | ||
| retention-days: 7 | ||
|
|
||
| - name: Upload container logs on failure | ||
| uses: actions/upload-artifact@v4 | ||
| if: failure() | ||
| with: | ||
| name: container-logs | ||
| path: tests/container_logs/ | ||
| retention-days: 7 | ||
|
|
||
| - name: Upload build logs | ||
| uses: actions/upload-artifact@v4 | ||
| if: always() | ||
| with: | ||
| name: build-logs | ||
| path: tests/build_logs/ | ||
| retention-days: 7 | ||
|
|
||
| - name: Cleanup Docker resources | ||
| if: always() | ||
| run: | | ||
| docker ps -aq --filter "name=ref_test_" | xargs -r docker rm -f || true | ||
| docker network ls -q --filter "name=ref_test_" | xargs -r docker network rm || true | ||
| docker volume ls -q --filter "name=ref_test_" | xargs -r docker volume rm || true |
| f"POSTGRES_PASSWORD={settings['secrets']['postgres_password']}", | ||
| "", | ||
| ] | ||
| SETTINGS_ENV.write_text("\n".join(lines)) |
| print() | ||
| print("Admin credentials for first login:") | ||
| print(" user: 0") | ||
| print(f" password: {settings['admin']['password']}") |
|
|
||
| # Connect via Rust proxy | ||
| client = paramiko.SSHClient() | ||
| client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) |
|
|
||
| # Connect via Rust proxy | ||
| client = paramiko.SSHClient() | ||
| client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) |
|
|
||
| # Connect via Rust proxy | ||
| client = paramiko.SSHClient() | ||
| client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) |
| pkey = paramiko.Ed25519Key.from_private_key(key_file) | ||
|
|
||
| client = paramiko.SSHClient() | ||
| client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) |
| pkey = paramiko.Ed25519Key.from_private_key(key_file) | ||
|
|
||
| client = paramiko.SSHClient() | ||
| client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) |
| invalid_key = paramiko.RSAKey.generate(2048) | ||
|
|
||
| client = paramiko.SSHClient() | ||
| client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) |
| valid_key = paramiko.Ed25519Key.from_private_key(key_file) | ||
|
|
||
| valid_client = paramiko.SSHClient() | ||
| valid_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) |
| pkey = paramiko.Ed25519Key.from_private_key(key_file) | ||
|
|
||
| client = paramiko.SSHClient() | ||
| client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.