diff --git a/.yardopts b/.yardopts index b8bb3a932..1868f39c7 100644 --- a/.yardopts +++ b/.yardopts @@ -8,6 +8,6 @@ cms/*.md data/*.md uml/*.md adr/*.md -RELEASE.md +RECOVERY.md GOV_ONE.md LICENSE diff --git a/Gemfile.lock b/Gemfile.lock index 84218b2c9..ab0c93117 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -317,7 +317,7 @@ GEM method_source (1.1.0) mini_mime (1.1.5) mini_portile2 (2.8.7) - minitest (5.24.1) + minitest (5.25.1) msgpack (1.7.2) multi_json (1.15.0) mutex_m (0.2.0) @@ -400,7 +400,7 @@ GEM hashie (>= 3, < 6) que (>= 0.14, < 3.0.0) raabro (1.4.0) - racc (1.8.0) + racc (1.8.1) rack (3.1.7) rack-mini-profiler (3.3.1) rack (>= 1.2.0) @@ -476,13 +476,13 @@ GEM rouge (4.2.0) rspec-core (3.13.0) rspec-support (~> 3.13.0) - rspec-expectations (3.13.1) + rspec-expectations (3.13.2) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-mocks (3.13.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (6.1.3) + rspec-rails (6.1.4) actionpack (>= 6.1) activesupport (>= 6.1) railties (>= 6.1) @@ -577,7 +577,7 @@ GEM faraday (~> 2.0) faraday-follow_redirects temple (0.10.3) - thor (1.3.1) + thor (1.3.2) tilt (2.3.0) timeout (0.4.1) trailblazer-option (0.1.2) @@ -619,7 +619,7 @@ GEM backports (>= 3.18) rainbow yard - zeitwerk (2.6.16) + zeitwerk (2.6.18) PLATFORMS aarch64-linux-musl diff --git a/RECOVERY.md b/RECOVERY.md new file mode 100644 index 000000000..b07f4683e --- /dev/null +++ b/RECOVERY.md @@ -0,0 +1,46 @@ +# Deployment and Content Maintenance and Recovery + +Rolling back a failed code release and restoring a database has been tested and there +is a strategy in place to provide the same assurances with content. + +However there are a number of improvements that could still be made: + + +### Recommendations + +1. + Ensure content restoration is possible whenever a coordinated code/content release is actioned. + + - Contentful does not provide the functionality, `Launch` to can only be used to publish. + - If multiple entries need to be reverted or unpublished then a pre-launch clone + of the environment must be made. + - This places a restriction on teams of content editors to pause work until the + success of the combined code and content release can be verified. + - There are a limited number of environments in the current plan so only one restore point of the master can + exist. + +2. + Synchronise the swap of web app and background worker and avoid deploying a worker when jobs are running. + + - The web server Azure AppService and background worker Azure Container share a + database however migrations are only run within the AppService after a blue/green swap. + - The worker will be recreated with new code before the web server can run any migrations it may require. + - The deployment may interrupt active mail or data export jobs. + +3. + Mail jobs now have the capacity use MailEvents from Notify callbacks to remove + users from the recipient scope ensuring that no duplicate messages are sent if the job is interrupted. + + - This is only implemented on the new module message but should be applied to all. + - Mail messages can also be rescheduled outside of working hours. + +4. + Concurrent jobs are guarded against. `v0.15.4` increases the export schedule from daily to every two days + to ensure an active job has time to complete and prevent the the next day's export from auto-expiring. + +3. + Increase the database server fast restore points in Azure to more than once in 24hrs + + - Additional cost may be incurred + + diff --git a/RELEASE.md b/RELEASE.md deleted file mode 100644 index 29a468f7f..000000000 --- a/RELEASE.md +++ /dev/null @@ -1,129 +0,0 @@ -# Delivery workflow - -We use 9 swim lanes on the [Jira][jira] board. - -**1. Sprint Backlog** - -- meets [definition of ready](#definition-of-ready) - -**2. Development** - -- active local development -- push to remote; the branch name must start with a ticket number, for example `ER-xxx` -- mark PR as `draft` and summarise deliverable -- associate to release candidate milestone - -**3. Blocked** - -- stalled or parked -- label PR as `blocked` - -**4. Developer Peer Review** - -- `content` deployment -- `ER-456` branch -- -- [feature deployments][deployments] -- meets [definition of done](#definition-of-done) -- mark PR as `ready` and [request review](#review-process) -- once approved move ticket to `#5` - -**5. Quality Assurance** - -- `content` deployment -- seek business analyst sign-off -- confirm the acceptance criteria -- label PR as `pass` or `fail` -- once passed merge to `main` branch and move ticket to `#6` - -**6. Integration** - -- `development` deployment -- `main` branch -- -- update accessibility and quality checks as required - -**7. Approval** - -- `staging` deployment -- `rcx.x.x` release candidate tag -- -- [open milestones (release candidates)][release-candidates] -- seek product owner sign-off - -**8. Release** - -- `production` deployment -- `vx.x.x` version tag -- -- [close milestone][released-versions] and rename from `rc` to `v` -- periodically publish a [release][releases] CHANGELOG - -**9. Post Release** - -- post release tasks - - -## Definition of Ready - -- description is clear and unambiguous -- acceptance criteria are present and understood -- ticket is estimated to be deliverable within a single sprint - -## Definition of Done - -- meets acceptance criteria -- includes appropriate documentation -- includes unit and feature tests -- maintains minimum coverage -- review app deployed -- deployment tested by the author - -## GitHub labels - -Github PRs use descriptive [labels][labels], most of which are applied automatically. - - -1. **adr**, Architectural Design Record. -1. **content**, Course and page content changes. -1. **dependencies**, Pull requests that update a dependency file. -1. **documentation**, Improvements or additions to documentation. -1. **frontend**, Changes to assets detected. -1. **pipeline**, Github workflow changes. -1. **ruby**, Pull requests that update Ruby code. -1. **terraform**, Changes to Terraform detected.. - -Manual labels: - -1. **blocked**, Currently blocked. -1. **review**, Review app deployed for testing. -1. **bug**, Squashes a bug. -1. **pass**, Acceptance criteria met. -1. **fail**, Acceptance criteria NOT met. - - - -## Application state - -- `Rails.application.live?` returns `true` if deployed as a final release to our public facing workspace. -- `Rails.application.debug?` returns `true` if running locally in development mode or as a feature peer review application. - -These two predicates can toggle "production", or "development" only features such as revealing debugging information. - - -## Dependencies - -Application libraries and workflow actions are monitored by [Dependabot][dependabot]. - - ---- - -[jira]: https://dfedigital.atlassian.net/jira/software/projects/ER -[deployments]: https://dfedigital.atlassian.net/jira/software/projects/ER/deployments - -[release-candidates]: https://github.com/DFE-Digital/early-years-foundation-recovery/milestones?state=open -[released-versions]: https://github.com/DFE-Digital/early-years-foundation-recovery/milestones?state=closed -[tags]: https://github.com/DFE-Digital/early-years-foundation-recovery/tags -[releases]: https://github.com/DFE-Digital/early-years-foundation-recovery/releases -[labels]: https://github.com/DFE-Digital/early-years-foundation-recovery/labels -[dependabot]: https://github.com/DFE-Digital/early-years-foundation-recovery/security/dependabot diff --git a/app/jobs/content_check_job.rb b/app/jobs/content_check_job.rb index c0d5b7d66..9477d2bc8 100644 --- a/app/jobs/content_check_job.rb +++ b/app/jobs/content_check_job.rb @@ -14,7 +14,7 @@ def valid? Training::Module.ordered.all? do |mod| check = ContentIntegrity.new(module_name: mod.name) check.call # print results - log Training::Module.cache.size # should be larger than 0 + # log Training::Module.cache.size # should be larger than 0 unless check.valid? log "#{mod.name} in '#{env}' via '#{api}' is not valid", :warn diff --git a/package.json b/package.json index d7f535ccc..16f5c8ba6 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "sass": "^1.77.8" }, "devDependencies": { - "stylelint": "^16.8.1", + "stylelint": "^16.9.0", "stylelint-config-gds": "^2.0.0" }, "stylelint": { diff --git a/spec/system/errors_spec.rb b/spec/system/errors_spec.rb index e79ebf550..74591eb42 100644 --- a/spec/system/errors_spec.rb +++ b/spec/system/errors_spec.rb @@ -20,4 +20,14 @@ expect(page).to have_content 'Sorry, there is a problem with the service' end end + + context 'when there is a service unavailable error' do + before do + visit '/503' + end + + specify do + expect(page).to have_content 'Service Unavailable' + end + end end diff --git a/yarn.lock b/yarn.lock index 78b3d967a..0aeb731ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34,38 +34,38 @@ __metadata: languageName: node linkType: hard -"@csstools/css-parser-algorithms@npm:^2.7.1": - version: 2.7.1 - resolution: "@csstools/css-parser-algorithms@npm:2.7.1" +"@csstools/css-parser-algorithms@npm:^3.0.1": + version: 3.0.1 + resolution: "@csstools/css-parser-algorithms@npm:3.0.1" peerDependencies: - "@csstools/css-tokenizer": ^2.4.1 - checksum: 939b23652c970dc4af8c20776e5da9e592cae4a590025f07ddb3263799076d4b6cf1bf8c4de97b29780bfa169177a31945effe94d2a11e0972138b5ff7d93654 + "@csstools/css-tokenizer": ^3.0.1 + checksum: 02649a70ab7bab1fd000ca1d196ffb93ad3e2e0f36b4aa064f7973cd31edc5f7e63f8eaf7b94d801a0bfd207386b8b23cbe40be6e871c27042b084c3a717349e languageName: node linkType: hard -"@csstools/css-tokenizer@npm:^2.4.1": - version: 2.4.1 - resolution: "@csstools/css-tokenizer@npm:2.4.1" - checksum: a368e5c96d3b11e147f95951e336105480acfa457cdbc6fdf97e8873ff92ab9ee6b4b6224ac1b263f08798802f6b29b8977a502d070f9ab695c9b9905b964198 +"@csstools/css-tokenizer@npm:^3.0.1": + version: 3.0.1 + resolution: "@csstools/css-tokenizer@npm:3.0.1" + checksum: 81ae01b2d3ec40ed3dc78f8507cbfdfe1dbc4ae3f8c8e29b8bb4414216a8c7a7a936fa0faa3d11a1e49ad72209aec7c05ad8450a4ffc30ba288aa074b4a0e3b3 languageName: node linkType: hard -"@csstools/media-query-list-parser@npm:^2.1.13": - version: 2.1.13 - resolution: "@csstools/media-query-list-parser@npm:2.1.13" +"@csstools/media-query-list-parser@npm:^3.0.1": + version: 3.0.1 + resolution: "@csstools/media-query-list-parser@npm:3.0.1" peerDependencies: - "@csstools/css-parser-algorithms": ^2.7.1 - "@csstools/css-tokenizer": ^2.4.1 - checksum: 4a771d94eb01a23279d493cd668c71ae230b660c1e6ebcff1bec6e959eae6987ece7ce01b094b44afbae8695dc98d8617580d488db16de9ec4a7378ed5adf57f + "@csstools/css-parser-algorithms": ^3.0.1 + "@csstools/css-tokenizer": ^3.0.1 + checksum: 794344c67b126ad93d516ab3f01254d44cfa794c3401e34e8cc62ddc7fc13c9ab6c76cb517b643dbda47b57f2eb578c6a11c4a9a4b516d88e260a4016b64ce7f languageName: node linkType: hard -"@csstools/selector-specificity@npm:^3.1.1": - version: 3.1.1 - resolution: "@csstools/selector-specificity@npm:3.1.1" +"@csstools/selector-specificity@npm:^4.0.0": + version: 4.0.0 + resolution: "@csstools/selector-specificity@npm:4.0.0" peerDependencies: - postcss-selector-parser: ^6.0.13 - checksum: 3786a6afea97b08ad739ee8f4004f7e0a9e25049cee13af809dbda6462090744012a54bd9275a44712791e8f103f85d21641f14e81799f9dab946b0459a5e1ef + postcss-selector-parser: ^6.1.0 + checksum: 7076c1d8af0fba94f06718f87fba5bfea583f39089efa906ae38b5ecd6912d3d5865f7047a871ac524b1057e4c970622b2ade456b90d69fb9393902250057994 languageName: node linkType: hard @@ -1182,7 +1182,7 @@ __metadata: govuk-frontend: "npm:^5.3.1" puppeteer: "npm:^22.14.0" sass: "npm:^1.77.8" - stylelint: "npm:^16.8.1" + stylelint: "npm:^16.9.0" stylelint-config-gds: "npm:^2.0.0" languageName: unknown linkType: soft @@ -1524,13 +1524,20 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.2.0, ignore@npm:^5.3.1": +"ignore@npm:^5.2.0": version: 5.3.1 resolution: "ignore@npm:5.3.1" checksum: 0a884c2fbc8c316f0b9f92beaf84464253b73230a4d4d286697be45fca081199191ca33e1c2e82d9e5f851f5e9a48a78e25a35c951e7eb41e59f150db3530065 languageName: node linkType: hard +"ignore@npm:^5.3.2": + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: cceb6a457000f8f6a50e1196429750d782afce5680dd878aa4221bd79972d68b3a55b4b1458fc682be978f4d3c6a249046aa0880637367216444ab7b014cfc98 + languageName: node + linkType: hard + "immutable@npm:^4.0.0": version: 4.3.6 resolution: "immutable@npm:4.3.6" @@ -1831,13 +1838,13 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:^4.0.4, micromatch@npm:^4.0.7": - version: 4.0.7 - resolution: "micromatch@npm:4.0.7" +"micromatch@npm:^4.0.4, micromatch@npm:^4.0.8": + version: 4.0.8 + resolution: "micromatch@npm:4.0.8" dependencies: braces: "npm:^3.0.3" picomatch: "npm:^2.3.1" - checksum: a11ed1cb67dcbbe9a5fc02c4062cf8bb0157d73bf86956003af8dcfdf9b287f9e15ec0f6d6925ff6b8b5b496202335e497b01de4d95ef6cf06411bc5e5c474a0 + checksum: 6bf2a01672e7965eb9941d1f02044fad2bd12486b5553dc1116ff24c09a8723157601dc992e74c911d896175918448762df3b3fd0a6b61037dd1a9766ddfbf58 languageName: node linkType: hard @@ -2158,10 +2165,10 @@ __metadata: languageName: node linkType: hard -"postcss-resolve-nested-selector@npm:^0.1.4": - version: 0.1.4 - resolution: "postcss-resolve-nested-selector@npm:0.1.4" - checksum: c53a1aa453690dacb9a34d60afb994c828779ad20d0abb8d7b37639f1144c0fd34f91e112cb7061f606d0459371c12463dae5777d465d4418fd20db054deb465 +"postcss-resolve-nested-selector@npm:^0.1.6": + version: 0.1.6 + resolution: "postcss-resolve-nested-selector@npm:0.1.6" + checksum: 85453901afe2a4db497b4e0d2c9cf2a097a08fa5d45bc646547025176217050334e423475519a1e6c74a1f31ade819d16bb37a39914e5321e250695ee3feea14 languageName: node linkType: hard @@ -2193,13 +2200,13 @@ __metadata: languageName: node linkType: hard -"postcss-selector-parser@npm:^6.1.1": - version: 6.1.1 - resolution: "postcss-selector-parser@npm:6.1.1" +"postcss-selector-parser@npm:^6.1.2": + version: 6.1.2 + resolution: "postcss-selector-parser@npm:6.1.2" dependencies: cssesc: "npm:^3.0.0" util-deprecate: "npm:^1.0.2" - checksum: ce2af36b56d9333a6873498d3b6ee858466ceb3e9560f998eeaf294e5c11cafffb122d307f3c2904ee8f87d12c71c5ab0b26ca4228b97b6c70b7d1e7cd9b5737 + checksum: 190034c94d809c115cd2f32ee6aade84e933450a43ec3899c3e78e7d7b33efd3a2a975bb45d7700b6c5b196c06a7d9acf3f1ba6f1d87032d9675a29d8bca1dd3 languageName: node linkType: hard @@ -2210,7 +2217,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.4.40": +"postcss@npm:^8.4.41": version: 8.4.41 resolution: "postcss@npm:8.4.41" dependencies: @@ -2665,14 +2672,14 @@ __metadata: languageName: node linkType: hard -"stylelint@npm:^16.8.1": - version: 16.8.1 - resolution: "stylelint@npm:16.8.1" +"stylelint@npm:^16.9.0": + version: 16.9.0 + resolution: "stylelint@npm:16.9.0" dependencies: - "@csstools/css-parser-algorithms": "npm:^2.7.1" - "@csstools/css-tokenizer": "npm:^2.4.1" - "@csstools/media-query-list-parser": "npm:^2.1.13" - "@csstools/selector-specificity": "npm:^3.1.1" + "@csstools/css-parser-algorithms": "npm:^3.0.1" + "@csstools/css-tokenizer": "npm:^3.0.1" + "@csstools/media-query-list-parser": "npm:^3.0.1" + "@csstools/selector-specificity": "npm:^4.0.0" "@dual-bundle/import-meta-resolve": "npm:^4.1.0" balanced-match: "npm:^2.0.0" colord: "npm:^2.9.3" @@ -2687,30 +2694,30 @@ __metadata: globby: "npm:^11.1.0" globjoin: "npm:^0.1.4" html-tags: "npm:^3.3.1" - ignore: "npm:^5.3.1" + ignore: "npm:^5.3.2" imurmurhash: "npm:^0.1.4" is-plain-object: "npm:^5.0.0" known-css-properties: "npm:^0.34.0" mathml-tag-names: "npm:^2.1.3" meow: "npm:^13.2.0" - micromatch: "npm:^4.0.7" + micromatch: "npm:^4.0.8" normalize-path: "npm:^3.0.0" picocolors: "npm:^1.0.1" - postcss: "npm:^8.4.40" - postcss-resolve-nested-selector: "npm:^0.1.4" + postcss: "npm:^8.4.41" + postcss-resolve-nested-selector: "npm:^0.1.6" postcss-safe-parser: "npm:^7.0.0" - postcss-selector-parser: "npm:^6.1.1" + postcss-selector-parser: "npm:^6.1.2" postcss-value-parser: "npm:^4.2.0" resolve-from: "npm:^5.0.0" string-width: "npm:^4.2.3" strip-ansi: "npm:^7.1.0" - supports-hyperlinks: "npm:^3.0.0" + supports-hyperlinks: "npm:^3.1.0" svg-tags: "npm:^1.0.0" table: "npm:^6.8.2" write-file-atomic: "npm:^5.0.1" bin: stylelint: bin/stylelint.mjs - checksum: 834d10490866b8472047938790f68cdc5bd298057ef7bfcf3be2e56259a8d3d05cbb66eefa235d603652fee92126e74d737ad40012721556c54d707407cbf7f1 + checksum: 0a7a697b066af36047fd02c952d59d5b26ac5db7f5772b75481310734c0e722970abb830d60460ea95afb618c51520cc09363dd9b83ae237afb0767b55fb0331 languageName: node linkType: hard @@ -2732,13 +2739,13 @@ __metadata: languageName: node linkType: hard -"supports-hyperlinks@npm:^3.0.0": - version: 3.0.0 - resolution: "supports-hyperlinks@npm:3.0.0" +"supports-hyperlinks@npm:^3.1.0": + version: 3.1.0 + resolution: "supports-hyperlinks@npm:3.1.0" dependencies: has-flag: "npm:^4.0.0" supports-color: "npm:^7.0.0" - checksum: 911075a412d8bcfbbca413e8963d56ed0975e35ff98d599ef85301aed4221428653145263828b6c58cb4cb6ff24596be83ead3cca221a88a70428af93d5e2a73 + checksum: e893fb035ecd86e42c5225dc1cd24db56eb950ed77b2e8f59c7aaf2836b8b2ef276ffd11f0df88b0b12184832aa2333f875eefcb74d3c47ed2633b6b41d4be43 languageName: node linkType: hard