# deployStatic

Deploys Simply Static exports from the build server to their public-facing ISPConfig sites: a pre-deploy backup, rsync over ssh, a remote `chown` to fix ownership, then (for sites with a formbridge form) a remote `--check-export` audit. Runs on the build server, as the account that holds ssh access to the public server.

## Relationship to formbridge

This is a general-purpose static-site deployment tool, not a formbridge component — it also deploys sites (e.g. `stargazer.rodolico.org`) with no formbridge involvement at all, and lives in its own repository here in `sysadmin_scripts`, independent of formbridge's.

For sites that *do* use a formbridge-signed contact form, this script optionally integrates with it: a pre-transfer sentinel check that the SSI include survived the export, a post-transfer `--check-export` audit run over `ssh` on the public server, and (§10.9, `formFields`) a rewriter that converts a WordPress form plugin's exported markup into what formbridge's signature format requires. All of it is config-gated per site (`formPages`/`formbridgeSiteId`/`formFields`/etc. in `sites.conf`) — a site with none of those keys set is deployed exactly like any other, with no formbridge dependency whatsoever.

formbridge's own repository, including the design documents referenced throughout this file (`ProjectDefinition.md` §10.8/§10.9, `Security.md`):

```
http://svn.dailydata.net/svn/formbridge/trunk
```

## Scripts

| Script | Purpose |
|---|---|
| `deployStatic` | Deploy one site, named by `--site`, per its entry in `sites.conf`. |

## Configuration

`sites.conf` (not shipped — see `sites.conf.sample` for the annotated template) is a Perl data file returning a hashref of site definitions, loaded relative to `deployStatic`'s own directory regardless of the caller's working directory. Copy `sites.conf.sample` to `sites.conf` and fill in each site's `from`/`to`/`user`/`group`/`sshHost`/`exclude`. `formPages`/`formbridgeSiteId` are optional per site — omit them for a site with no formbridge form deployed yet; the form-related checks below are skipped, not failed, when absent.

## What a deploy does

1. **Form rewriting** (only if `formFields` is set for this site). Converts a WordPress form plugin's exported markup into something formbridge accepts — renames fields, fixes the `action` URL, inserts the SSI include, strips the plugin's now-dead JavaScript — while leaving every `class`/`id`/label alone so the form keeps the site's own styling. This lets a designer keep using the plugin's UI instead of a bare Custom HTML block. Runs against an isolated **staging copy** of the export, never the export itself — re-running a deploy against the same (unrefreshed) export stays safe, since the plugin's original field names are still there to rewrite from. See formbridge's `Documentation/ProjectDefinition.md` §10.9 (repository pointer above) for the full design, including the three assertions that abort the deploy on a stale or incomplete `formFields` mapping.
2. **Pre-deploy backup.** `cp -al` of the live docroot to `<siteRoot>/private/deploy-backup-<timestamp>/web`, outside the rsync destination so `--delete` never touches it. Hardlinked, so it costs almost nothing in time or space — but only stays that way if rsync never receives `--inplace`, which would edit the backup along with the live tree instead of replacing files via rename. The last 7 backups per site are kept (`backupRetention` in `sites.conf` to override); older ones are pruned automatically after each successful backup.
3. **Tier-1 check.** Before transfer, if `formPages` is set: confirm each listed exported page (post-rewrite, for a `formFields` site) still contains the SSI include (`<!--#include virtual=`). Catches a minifier having stripped it, before anything reaches the public server.
4. **rsync**, with `--checksum` (so unchanged files are skipped and the backup's hardlinks survive) and `--chmod=D755,F644` (applied during transfer, so it can never touch the excluded `fpc/`).
5. **Remote `chown -R`.**
6. **Tier-2 check.** If `formbridgeSiteId` is set: `ssh`'s into the public server and runs formbridge's `--check-export` against the deployed bytes — the config-aware audit (declared fields present, no baked `fpc_*` inputs, correct `action` URL) that only the public server can do, since that is where `etc/forms.d/*.json` lives. On failure, **the deploy is not rolled back automatically** — the script prints and logs the specific check failures plus the exact `rsync` command to restore from the backup taken in step 2, and exits non-zero.

## Usage

Required: `--site NAME`, matching a `name` entry in `sites.conf`.

Optional:

- `--dry-run` — passes `--dry-run` through to rsync and skips the remote `chown`; still runs the export sanity check and logs what it would have done.
- `--show` — prints the rsync command that would run and exits, without touching the export or requiring it to exist. Useful for checking a `sites.conf` edit before trusting it to a live deploy.

Every run appends to `/var/log/site-sync/<siteName>.log`, including the full output of the rsync and ssh commands — that log is the only failure notification this script has today.

```
# Deploy one site
./deployStatic --site example

# Check what a config change would do before running it for real
./deployStatic --site example --dry-run
```

### Cron

```cron
15 2 * * * cd /opt/deployStatic && ./deployStatic --site example >> /var/log/site-sync/example.cron.log 2>&1
```

There is no `--quiet` flag: on success the script is already silent on the terminal apart from what rsync/ssh print, and everything is duplicated into the per-site log regardless, so redirecting stdout/stderr in the crontab line above is a safety net rather than the primary record.
