Skip to content
English
  • There are no suggestions because the search field is empty.

02.01 The Upgrade Process

How SimpleRisk upgrades — the version stamp in version.php, the $releases chain in upgrade.php, the upgrade_from_ functions that walk the chain forward, the database version tracked in the settings table, and the deployment-shape-specific workflows in the rest of this chapter.

Why this matters

SimpleRisk releases roughly every two to three months. Each release ships application code changes, sometimes ships database schema changes, and accumulates against the prior release rather than replacing it. Upgrades are how an installation moves from one release to the next; the upgrade is what runs the schema migrations that keep the database in sync with the application code.

Understanding the upgrade architecture matters because it shapes the operator's mental model for everything else in this chapter. Once you know that:

  • The application carries an APP_VERSION constant in simplerisk/includes/version.php.
  • The database carries a db_version value in the settings table.
  • The upgrade walks the chain of upgrade_from_ ($db) functions in simplerisk/includes/upgrade.php until those two values match.
  • The chain is a list of every released version (the $releases array near the top of upgrade.php).
  • Each function in the chain does its specific upgrade work and atomically updates settings.db_version to the next version in the chain.

— then the deployment-specific upgrade workflows (Upgrading via Docker, Upgrading on Bare Metal, Upgrading Extras) all make sense as variations on the same underlying mechanism.

The other thing worth knowing: upgrades are not optional. SimpleRisk's release cadence includes security patches that don't backport to old versions. An installation running on a version released two years ago is exposed to whatever security issues have been fixed since. The upgrade discipline is part of the program's security posture, not an optional convenience.

The third thing: Extras upgrade separately from Core. Each Extra has its own version-tracking and its own upgrade chain ( _extra_version in settings, upgrade_ _extra_database() function in the Extra). A Core upgrade doesn't automatically bring the Extras forward — they have their own workflow, documented in Upgrading Extras.

How frameworks describe this

Frameworks generally don't prescribe specific upgrade processes (that's vendor-specific) but they do require organizations to keep their software current as part of broader vulnerability management.

  • NIST SP 800-53 SI-2 (Flaw Remediation) explicitly mandates that the organization identify, report, and correct information system flaws, including patches and updates. SimpleRisk upgrades fit under SI-2 directly.
  • CIS Critical Security Controls v8 Control 7 (Continuous Vulnerability Management) includes patching as a core practice.
  • PCI DSS v4.0 Requirement 6.3.3 mandates that all in-scope system components have all known security vulnerabilities addressed within an organization-defined timeframe (typically 30 days for critical, 90 days for high).
  • ISO/IEC 27001 Annex A A.8.8 (Management of technical vulnerabilities) requires the organization to have a documented vulnerability-management process that includes timely patching.

For programs running SimpleRisk under any of these regimes, "we're still on the version from 18 months ago" isn't a defensible answer. The upgrade cadence needs to keep pace with the release cadence, with documented exception handling for cases where an upgrade has to wait.

How SimpleRisk implements this

Version stamps

Two version values matter:

  • APP_VERSION — defined in simplerisk/includes/version.php as a PHP constant. The format is YYYYMMDD-VVV (e.g., 20260422-001). This is the version of the application code currently deployed.
  • db_version — stored in the settings table with key db_version and value in the same YYYYMMDD-VVV format. This is the version the database schema is currently at.

These two values may not match for short windows: when you replace the application files (Docker image swap, or tar-extract on bare metal) but haven't yet run the database upgrade, APP_VERSION is the new release and db_version is the old release. The upgrade workflow brings db_version up to match APP_VERSION.

The two helpers that read these values:

  • current_version("app") — returns APP_VERSION.
  • current_version("db") — returns the db_version from the settings table.

The $releases chain

simplerisk/includes/upgrade.php opens with a global $releases array listing every released version in order, oldest first. The current array holds versions stretching back to 20140728-001 and forward to the current release. Each entry corresponds to an upgrade_from_ ($db) function defined later in the same file.

The function naming convention is the version string with the dashes removed:

  • Version 20260422-001upgrade_from_20260422001($db)
  • Version 20260224-001upgrade_from_20260224001($db)

Each function does the schema migration work for the version it's named after (CREATE TABLE, ALTER TABLE, UPDATE settings SET ..., seed-data inserts, whatever the release needs) and ends with a call to update_database_version($db, $version_to_upgrade, $version_upgrading_to) that atomically moves db_version to the next entry in the $releases chain.

How upgrade_database() walks the chain

The driver function is upgrade_database(). It runs in a recursive pattern:

  1. Read the current APP_VERSION from version.php.
  2. Read the current db_version from the settings table.
  3. If they're equal, the database is up to date. Return.
  4. Find the upgrade function for the current db_version via get_database_upgrade_function_for_release(). This returns the function name upgrade_from_ that knows how to move from the current version to the next.
  5. Invoke that function via call_user_func().
  6. The function does its work, then calls update_database_version() to bump db_version to the next entry in the chain.
  7. Recurse: call upgrade_database() again. The new db_version is now compared against APP_VERSION; if they match, return; otherwise, continue the chain.

The recursion handles the case where the application has jumped multiple versions (e.g., the operator skipped two releases and is now upgrading three versions at once). Each upgrade function in the chain runs in turn until the database catches up.

The atomicity comes from the update_database_version() helper, which uses a conditional UPDATE (UPDATE settings SET value=:to WHERE name='db_version' AND value=:from). If the current db_version doesn't match what the upgrade function expected (because another concurrent upgrade is in progress), the UPDATE affects zero rows and the function detects the conflict, preventing partial states.

The upgrade UI and API

Two operator-facing entry points:

  • /admin/upgrade.php — the browser-based upgrade UI. Requires admin login. Walks the schema upgrade and reports progress. Use this for interactive upgrades.
  • GET /api/upgrade/upgrade/simplerisk/db — the API entry point for programmatic upgrades. Authenticates via the standard API key mechanism. Use this for scripted upgrades or for orchestration in CI/CD-driven deployments.

Several related API routes exist for full-stack upgrade orchestration:

  • GET /api/upgrade/version/app — get the current APP_VERSION.
  • GET /api/upgrade/backup/app — back up the application files (used in the standard upgrade workflow).
  • GET /api/upgrade/backup/db — back up the database (used in the standard upgrade workflow).
  • GET /api/upgrade/upgrade/simplerisk/app — upgrade the application files (Docker image swap, file replacement; the API endpoint orchestrates this for some deployment shapes).
  • GET /api/upgrade/upgrade/simplerisk/db — run the database upgrade (the main programmatic entry point).
  • Per-extra: GET /api/ /upgrade/app for each Extra's upgrade.

These endpoints live in the Upgrade Extra at simplerisk/extras/upgrade/includes/api.php (which itself is an Extra and may need its own activation; for installations that don't activate it, the browser-based /admin/upgrade.php is the upgrade path).

Special handling during upgrade

The upgrade flow deliberately bypasses several security checks that apply during normal operation:

  • Account lockout after failed login attempts — disabled during upgrade, so an admin locked out of normal sessions can still log in to run an upgrade.
  • MFA enforcement — disabled during upgrade.
  • Forced password change — disabled during upgrade.

The reasoning: an upgrade is by definition a recovery scenario where the database schema may be mid-migration; requiring the full normal-operation security flow could prevent the operator from completing the upgrade. The trade-off is documented; if your security policy doesn't permit the bypass, run upgrades from a controlled environment with the same physical/network controls you'd require for any privileged operation.

The upgrade flow also runs in its own session namespace (SimpleRiskDBUpgrade rather than the main app session) so an upgrade in progress doesn't contaminate normal user sessions.

Post-upgrade housekeeping

After the chain of upgrade functions completes, the upgrade flow runs two normalization passes:

  • convert_tables_to_innodb($db) — alters all tables (except sessions) to InnoDB engine. Some older tables may have been MyISAM from earlier installations; this brings them all to InnoDB for transactional consistency.
  • convert_tables_to_utf8($db) — alters all tables to utf8mb4_general_ci collation. Ensures the database can handle the full Unicode range that the multi-language UI requires.

These are idempotent (running them on already-converted tables is a no-op) so they're safe to re-run.

Database privilege requirements

The upgrade flow runs check_grants($db) early to verify the SimpleRisk MySQL user has the privileges the upgrade needs: SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, REFERENCES, INDEX. These are the same privileges granted during the initial install (Step 6 of the wizard); upgrades don't need additional grants beyond what install needed.

If check_grants() fails (because the privileges have been narrowed since install, or because a different MySQL user is being used), the upgrade returns a clear error listing the missing privileges. Either grant them temporarily for the upgrade or use a different connection that has them.

Common pitfalls

A handful of patterns recur with SimpleRisk upgrades.

  • Skipping the application-files step. The two-part upgrade is "swap the files" (new image / new tarball) plus "run the database upgrade" (the chain of upgrade_from_* functions). Skipping the file swap leaves the application code at the old version even after the database has migrated; the symptoms range from confusing UI behavior to outright errors. Always do both parts; the deployment-shape-specific articles (Upgrading via Docker, Upgrading on Bare Metal) document the specific sequence.

  • Skipping the database upgrade after the file swap. The mirror failure: new application code, old database schema. The application starts erroring as code paths try to use schema elements that don't exist yet. After replacing the application files, run the database upgrade promptly — either via /admin/upgrade.php or via GET /api/upgrade/upgrade/simplerisk/db.

  • Upgrading without a backup. The single most common operator regret. The upgrade is generally reliable but the schema changes are not trivially reversible without a database backup. Take a backup before any upgrade; see Database Backup and Restore. The backup is the rollback path; without it, a failed upgrade is recoverable only by running the upgrade forward through whatever issue blocked it.

  • Letting the upgrade chain stretch too far. Skipping releases is supported (the chain handles it), but the longer the chain, the more upgrade functions run in series, and the more chance for a failure mid-chain to leave the database in an indeterminate state. For installations that have skipped many releases, consider upgrading through intermediate versions (release-by-release) rather than jumping the entire gap in one upgrade. The intermediate steps are testable independently.

  • Not reading the release notes. Each release's notes (under release_notes/ in the SimpleRisk repository) document what changed, including upgrade-specific notes (data migrations that take significant time, configuration settings that need attention, deprecations). Reading the notes for the versions you're skipping over is part of the upgrade preparation.

  • Forgetting to upgrade the Extras. Core upgrades don't trigger Extra upgrades. After a Core upgrade, walk the activated Extras and verify each is at the version expected for the new Core release. The per-Extra upgrade workflow is in Upgrading Extras.

  • Running the upgrade UI from a session that's about to time out. Long upgrades (multi-version chains, large databases) can take many minutes. A session that times out mid-upgrade can leave the operator unable to monitor the completion. Use the API path for long upgrades, or extend the session timeout temporarily.

  • Running the upgrade against a database with active production load. The schema changes can lock tables or run for minutes; concurrent application traffic against the same tables can fail. For high-traffic installations, schedule the upgrade during a maintenance window with the application disabled (or in maintenance mode) for the duration of the upgrade.

  • Treating the upgrade-mode security bypass as a permanent escape hatch. The bypass exists for upgrade-time scenarios. Don't rely on it for routine admin access; if you're doing admin work outside an actual upgrade, run through the normal authentication flow (with MFA if configured).

Related

Reference

  • Permission required: check_admin for the /admin/upgrade.php UI; valid API key for the v2 API endpoints.
  • API endpoint(s): GET /api/upgrade/version/app (get APP_VERSION); GET /api/upgrade/backup/app and GET /api/upgrade/backup/db (orchestrated backups); GET /api/upgrade/upgrade/simplerisk/app (file-swap, deployment-shape-specific); GET /api/upgrade/upgrade/simplerisk/db (the database upgrade — main programmatic entry point); per-Extra GET /api/ /upgrade/app .
  • Implementing files: simplerisk/includes/version.php (the APP_VERSION constant); simplerisk/includes/upgrade.php (the $releases chain, the upgrade_from_ () functions, the upgrade_database() driver, the update_database_version() and get_database_upgrade_function_for_release() helpers); simplerisk/admin/upgrade.php (the browser UI); simplerisk/extras/upgrade/includes/api.php (the v2 API surface).
  • Database tables: settings (the db_version and api_key keys); the schema of every other table is what the upgrade functions modify.
  • config_settings keys: db_version (the database version stamp); api_key (used by the API-key-based upgrade authentication).
  • External dependencies: None for the upgrade itself; outbound HTTPS to the SimpleRisk content sources may be relevant for some Extras' upgrade flows (e.g., the SCF Extra's content updates).