fix(17): T-17-15 refuse an unsafe frontend_url on save and import
- Settings.BeforeValidate answers a cabana validation error on frontend_url, so the settings save is a 422 and the row is unchanged - sitemap:import-winter stops on a frontend_url that models.AllowedFrontendURL refuses, before the dry-run branch and before any database use; the value is printed quoted - errors.frontend_url phrase in en and pl - TestSettingsBeforeValidate, TestWinterSettingsFrontendURL and the save and import refusals in the Postgres smokes
This commit is contained in:
10
README.md
10
README.md
@@ -109,6 +109,8 @@ A save also refuses, per row, a missing `reference` for a registry type that tak
|
||||
| `enable_priority_tiers` | on | Tier priorities replace item priorities. |
|
||||
| `priority_homepage`, `priority_services`, `priority_blog`, `priority_categories`, `priority_legal` | `1.0`, `0.8`, `0.6`, `0.4`, `0.2` | The tier values, stored as text. |
|
||||
|
||||
A save refuses a `frontend_url` outside the accepted form with a 422 keyed `frontend_url` (phrase `golem15.sitemap::lang.errors.frontend_url`), and `sitemap:import-winter` stops with an error. The PHP plugin stored any text and wrote it unescaped into `<loc>`, the hreflang links and the stylesheet instruction.
|
||||
|
||||
The updates manifest is read only when it is a regular file of at most 5 MiB (`classes.ManifestMaxBytes`) holding a JSON object; paths match with the leading slash added and the trailing slash removed (`/` stays). Any error omits `lastmod` and is logged without the file's content. The manifest is a frontend build output, for example a script that writes the git commit date of each static page's source:
|
||||
|
||||
```json
|
||||
@@ -191,7 +193,7 @@ The WinterCMS forms are adapted to the admin's YAML:
|
||||
| `models.DefinitionItem`, `models.DefinitionItems` | One item and the stored list, with the tolerant PHP-shaped decoding. |
|
||||
| `models.ItemTypeURL` | The built-in item type `url`. |
|
||||
| `models.Text`, `models.DecodeText` | A text field's value; the tolerant decoding of one stored text value. |
|
||||
| `models.Settings`, `models.DefaultSettings` | The settings row and its PHP defaults; `Settings.Priority` reads a tier value. |
|
||||
| `models.Settings`, `models.DefaultSettings` | The settings row and its PHP defaults; `Settings.Priority` reads a tier value, `Settings.BeforeValidate` refuses a `frontend_url` outside the accepted form on a save. |
|
||||
| `models.AllowedFrontendURL` | Whether a value may be the `frontend_url` setting: empty, or an absolute `http`/`https` URL with a host and without whitespace, control characters, `"`, `<`, `>` or `&`. |
|
||||
| `models.PriorityHomepage`, `models.PriorityServices`, `models.PriorityBlog`, `models.PriorityCategories`, `models.PriorityLegal`, `models.PriorityDefaults` | The tier setting keys and their defaults. |
|
||||
| `controllers.DefinitionsControllerID`, `controllers.PermissionAccessDefinitions` | `golem15.sitemap.definitions` and `golem15.sitemap.access_definitions`. |
|
||||
@@ -214,7 +216,7 @@ The WinterCMS forms are adapted to the admin's YAML:
|
||||
| Command | Arguments and flags | Effect |
|
||||
|---------|---------------------|--------|
|
||||
| `sitemap:import` | `FILE`, `--theme`, `--append` | The PHP `ImportCommand`: reads a JSON array of `{url, changefreq, priority}` entries (`monthly` and `0.5` by default). Without `--append` the definition keeps its non-URL items first and the imported URLs replace its URL items; with it the URLs follow every existing item. The definition is always `default`; a `--theme` other than `default` is reported. An entry whose URL `classes.AllowedItemURL` refuses stops the import. |
|
||||
| `sitemap:import-winter` | `--definitions FILE`, `--settings FILE`, `--theme`, `--map old=new` (repeatable), `--page-url reference=/path` (repeatable), `--force`, `--dry-run` | Copies a WinterCMS export into the definition and the settings row. URL items are kept; static and CMS page items are dropped unless `--page-url` names the URL of their reference (for example `--page-url blog=/blog` copies the CMS page item `blog` as a url item `/blog`); `--map` renames types first (for example `--map blog-post=journal-post`); an item of an unknown type, or whose reference is not among its type's current references, is dropped; a url item whose URL `classes.AllowedItemURL` refuses is dropped, and so is a page item whose `--page-url` it refuses; a `urlPattern` that is not a path is cleared. Every dropped, remapped or cleared item and every dropped `cmsPage` is printed. A definition that already has items is refused without `--force`; `--dry-run` writes nothing. Settings missing from the export take the defaults. `--theme` picks a definition when the export holds several. |
|
||||
| `sitemap:import-winter` | `--definitions FILE`, `--settings FILE`, `--theme`, `--map old=new` (repeatable), `--page-url reference=/path` (repeatable), `--force`, `--dry-run` | Copies a WinterCMS export into the definition and the settings row. URL items are kept; static and CMS page items are dropped unless `--page-url` names the URL of their reference (for example `--page-url blog=/blog` copies the CMS page item `blog` as a url item `/blog`); `--map` renames types first (for example `--map blog-post=journal-post`); an item of an unknown type, or whose reference is not among its type's current references, is dropped; a url item whose URL `classes.AllowedItemURL` refuses is dropped, and so is a page item whose `--page-url` it refuses; a `urlPattern` that is not a path is cleared. Every dropped, remapped or cleared item and every dropped `cmsPage` is printed. A definition that already has items is refused without `--force`; `--dry-run` writes nothing. Settings missing from the export take the defaults; a `frontend_url` which `models.AllowedFrontendURL` refuses stops the import before anything is written, also with `--dry-run`. `--theme` picks a definition when the export holds several. |
|
||||
|
||||
Both commands open the database themselves when the application has not published one.
|
||||
|
||||
@@ -229,7 +231,7 @@ mysql -N -B --raw <database> < scripts/winter-export-settings.sql > sitemap-sett
|
||||
|
||||
## Dependencies
|
||||
|
||||
- SummerCMS modules: backpack, bonfire, compass, festival, lagoon, pact, party, signpost, surf; bouncer and cabana in tests.
|
||||
- SummerCMS modules: backpack, bonfire, cabana, compass, festival, lagoon, pact, party, signpost, surf; bouncer in tests. cabana is a regular dependency: `models` and `controllers` return its validation error.
|
||||
- Third-party: `gorm.io/gorm`, `github.com/go-gormigrate/gormigrate/v2`. Test-only: `github.com/testcontainers/testcontainers-go`, `github.com/jackc/pgx/v5`.
|
||||
|
||||
## Testing
|
||||
@@ -239,7 +241,7 @@ go test -short ./... # goldens and config checks, no Docker
|
||||
go test ./... # also the Postgres smoke tests
|
||||
```
|
||||
|
||||
`TestSitemapGolden` (`classes`) feeds `testdata/tracer.json`, `urlto.json` and `full.json` through the Go port and compares bytes with the goldens; it also checks the 50000 URL cap. `TestSitemapTiersConfig` checks the tier rule refusals, a host's replacement of the rule list and the manifest's fail-safe reads. The Postgres smokes (`TestSitemapTracer`, `TestSitemapImportSmoke`, `TestSitemapAdminSmoke`) boot the plugin with a test content plugin and drive the routes, the import commands and the admin API.
|
||||
`TestSitemapGolden` (`classes`) feeds `testdata/tracer.json`, `urlto.json` and `full.json` through the Go port and compares bytes with the goldens; it also checks the 50000 URL cap. `TestSitemapTiersConfig` checks the tier rule refusals, a host's replacement of the rule list and the manifest's fail-safe reads. `TestRewriteUnsafeFrontendURL` (`classes`), `TestAllowedFrontendURL` and `TestSettingsBeforeValidate` (`models`) and `TestWinterSettingsFrontendURL` (`console`) are the Docker-free checks of the `frontend_url` rules: the accepted form, the rewrite that is not applied for any other value, the save hook and the import refusal. The Postgres smokes (`TestSitemapTracer`, `TestSitemapImportSmoke`, `TestSitemapAdminSmoke`, `TestImportWinter`, `TestSitemapCacheAndThrottle`) boot the plugin with a test content plugin and drive the routes, the import commands and the admin API; they cover the 422 of a refused `frontend_url` save and a value stored straight in the row, which the sitemap does not apply.
|
||||
|
||||
The goldens are generated from the PHP plugin's generation code and the vendored Winter URL generator of any WinterCMS application, and committed, so CI needs no PHP:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user