Skip to content

Commit c5afb5d

Browse files
committed
CCM-11207: need a spec to gen from
1 parent 160c09f commit c5afb5d

File tree

12 files changed

+700
-11
lines changed

12 files changed

+700
-11
lines changed

docs/_config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ just_the_docs:
5353
# Supports true or false (default)
5454
nav_fold: false # note: this option is new in v0.4
5555
# Exclude the collection from the search
56-
# Supports true or false (defaul
56+
# Supports true or false (default)
5757
search_exclude: false
5858

5959
defaults:
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
---
22
title: Architecture & Design
3-
order: 0
4-
nav_order: 5
3+
nav_order: 2
54
has_children: true
65
has_toc: true
76
---

docs/collections/_developers/getting-started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: API Developers - Getting Started
33
order: 0
4-
nav_order: 4
4+
nav_order: 1
55
has_children: false
66
has_toc: false
77
---
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
---
2+
3+
title: Bash and Make
4+
parent: Developer Guides
5+
---
6+
7+
## Developer Guide: Bash and Make
8+
9+
- [Developer Guide: Bash and Make](#developer-guide-bash-and-make)
10+
- [Using Make](#using-make)
11+
- [Using Bash](#using-bash)
12+
- [Make and Bash working together](#make-and-bash-working-together)
13+
- [Conventions](#conventions)
14+
- [Debugging](#debugging)
15+
- [Scripts](#scripts)
16+
17+
## Using Make
18+
19+
Sample make target signature definition:
20+
21+
```makefile
22+
some-target: # Target description - mandatory: foo=[description]; optional: baz=[description, default is 'qux'] @Category
23+
# Recipe implementation...
24+
```
25+
26+
- `some-target`: This is the name of the target you would specify when you want to run this particular target. Use the kebab-case naming convention and prefix with an underscore `_` to mark it as a "private" target. The first part of the name is used for grouping, e.g. `docker-*` or `terraform-*`.
27+
- `Target Description`: Provided directly after the target name as a single line, so be concise.
28+
- `mandatory` parameters: Parameters that must be provided when invoking the target. Each parameter has its own description. Please follow the specified format as it is used by `make help`.
29+
- `optional` parameters: Parameters that are not required when invoking the target. They may have a default value. Each parameter has its own description.
30+
- `@Category` label: Used for grouping by the `make help` command.
31+
- `Recipe implementation`: This section defines the actual commands or steps the target will execute. **Do not exceed 5 lines of effective code**. For more complex operations, use a shell script. Refer to the `docker-build` implementation in the [docker.mk](../../scripts/docker/docker.mk) file. More complex operations are implemented in the [docker.sh](../../scripts/docker/docker.lib.sh) script for readability and simplicity.
32+
33+
Run make target from a terminal:
34+
35+
```shell
36+
foo=bar make some-target # Environment variable is passed to the make target execution process
37+
make some-target foo=bar # Make argument is passed to the make target execution process
38+
```
39+
40+
By convention we use uppercase variables for global settings that you would ordinarily associate with environment variables. We use lower-case variables as arguments to call functions or make targets, in this case.
41+
42+
All make targets should be added to the `${VERBOSE}.SILENT:` section of the `make` file, which prevents `make` from printing commands before executing them. The `${VERBOSE}` prefix on the `.SILENT:` special target allows toggling it if needed. If you explicitly want output from a certain line, use `echo`.
43+
44+
It is worth noting that by default, `make` creates a new system process to execute each line of a recipe. This is not the desired behaviour for us and the entire content of a make recipe (a target) should be run in a single shell invocation. This has been configured in this repository by setting the [`.ONESHELL:`](https://www.gnu.org/software/make/manual/html_node/One-Shell.html) special target in the `scripts/init.mk` file.
45+
46+
To see all available make targets, run `make help`.
47+
48+
## Using Bash
49+
50+
When working in the command-line ensure the environment variables are reset to their initial state. This can be done by reloading shell using the `env -i $SHELL` command.
51+
52+
Sample Bash function definition:
53+
54+
```shell
55+
# Short function description
56+
# Arguments (provided as environment variables):
57+
# foo=[description]
58+
# baz=[description, default is 'qux']
59+
function some-shell-function() {
60+
# Function implementation...
61+
```
62+
63+
Run Bash function from a terminal:
64+
65+
```shell
66+
source scripts/a-suite-of-shell-functions
67+
foo=bar some-shell-function # Environment variable is accessible by the function executed in the same operating system process
68+
```
69+
70+
```shell
71+
source scripts/a-suite-of-shell-functions
72+
foo=bar
73+
some-shell-function # Environment variable is still accessible by the function
74+
```
75+
76+
Run Bash script from a terminal, bear in mind that executing a script creates a child operating system process:
77+
78+
```shell
79+
# Environment variable has to be exported to be passed to a child process, DO NOT use this pattern
80+
export foo=bar
81+
scripts/a-shell-script
82+
```
83+
84+
```shell
85+
# or to be set in the same line before creating a new process, prefer this pattern over the previous one
86+
foo=bar scripts/a-shell-script
87+
88+
# or when multiple variables are required
89+
foo=bar \
90+
baz=qux \
91+
scripts/a-shell-script
92+
```
93+
94+
By convention we use uppercase variables for global settings that you would ordinarily associate with environment variables. We use lower-case variables as arguments to be passed into specific functions we call, usually on the same line, right before the function name.
95+
96+
The command `set -euo pipefail` is commonly used in the Bash scripts, to configure the behavior of the script in a way that makes it more robust and easier to debug. Here is a breakdown of each option switch:
97+
98+
- `-e`: Ensures that the script exits immediately if any command returns a non-zero exit status.
99+
- `-u`: Makes the script exit if there is an attempt to use an uninitialised variable.
100+
- `-o pipefail`: ensures that if any command in a pipeline fails (i.e., returns a non-zero exit status), then the entire pipeline will return that non-zero status. By default, a pipeline returns the exit status of the last command.
101+
102+
## Make and Bash working together
103+
104+
Sample make target calling a Bash function. Notice that `baz` is going to be accessible to the function as it is executed in the same operating system process:
105+
106+
```makefile
107+
some-target: # Run shell function - mandatory: foo=[description]
108+
source scripts/a-suite-of-shell-function
109+
baz=qux
110+
some-shell-function # 'foo' and 'baz' are accessible by the function
111+
```
112+
113+
Sample make target calling another make target. In this case a parameter `baz` has to be passed as a variable to the make target, which is executed in a child process:
114+
115+
```makefile
116+
some-target: # Call another target - mandatory: foo=[description]
117+
baz=qux \
118+
make another-target # 'foo' and 'baz' are passed to the make target
119+
```
120+
121+
Run it from a terminal:
122+
123+
```shell
124+
foo=bar make some-target
125+
```
126+
127+
## Conventions
128+
129+
### Debugging
130+
131+
To assist in investigating scripting issues, the `VERBOSE` variable is available for both Make and Bash scripts. If it is set to `true` or `1`, it prints all the commands that the script executes to the standard output. Here is how to use it:
132+
133+
for Make targets
134+
135+
```shell
136+
VERBOSE=1 make docker-example-build
137+
```
138+
139+
for Bash scripts
140+
141+
```shell
142+
VERBOSE=1 scripts/shellscript-linter.sh
143+
```
144+
145+
### Scripts
146+
147+
Most scripts provided with this repository template can use tools installed on your `PATH` if they are available or run them from within a Docker container. To force a script to use Docker, the `FORCE_USE_DOCKER` variable is provided. This feature allows you to use custom tooling if it is present on the command-line path. Here is how to use it:
148+
149+
```shell
150+
FORCE_USE_DOCKER=1 scripts/shellscript-linter.sh
151+
```
152+
153+
You can combine it with the `VERBOSE` flag to see the details of the execution flow:
154+
155+
```shell
156+
VERBOSE=1 FORCE_USE_DOCKER=1 scripts/shellscript-linter.sh
157+
```
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
title: Developer Guides
3+
nav_order: 3
4+
has_children: true
5+
has_toc: true
6+
---
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
title: Git
3+
parent: Developer Guides
4+
description: Getting started with Git
5+
summary: Getting started with Git
6+
last_modified_date: 2024-05-28
7+
---
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
---
2+
title: GitHub Configuration
3+
parent: Developer Guides
4+
description: Configuring new GitHub repositories for use within NHS Notify
5+
summary: Configuring new GitHub repositories for use within NHS Notify
6+
last_modified_date: 2024-05-28
7+
---
8+
9+
When setting up a new GitHub repository for use with NHS Notify, we use a standard set of configuration options to
10+
ensure consistency and security.
11+
12+
This guide follows the NHSE Software Engineering Quality Framework, in particular the following pages are useful:
13+
14+
* [Securing Repositories](https://github.com/NHSDigital/software-engineering-quality-framework/blob/main/practices/securing-repositories.md#securing-repositories)
15+
* [Continuous Integration](https://github.com/NHSDigital/software-engineering-quality-framework/blob/main/practices/continuous-integration.md)
16+
17+
## Codeowners
18+
19+
Following
20+
the [SEQF guidance](https://github.com/NHSDigital/software-engineering-quality-framework/blob/main/practices/securing-repositories.md#teams-setup),
21+
the default code owner should be the GitHub team with write access to the repository.
22+
23+
In addition, due to the multi-repository structure of the codebase, the CODEOWNERS files themselves are protected by
24+
requiring approval from a project-wide nhs-notify-code-owners team.
25+
26+
For example:
27+
28+
```codeowners
29+
# Default codeowner should be a team with write access
30+
* @NHSDigital/nhs-notify-amet
31+
32+
# Default protection for codeowners, must be last in file
33+
/.github/CODEOWNERS @NHSDigital/nhs-notify-code-owners
34+
/CODEOWNERS @NHSDigital/nhs-notify-code-owners
35+
```
36+
37+
Individual teams are encouraged to include additional codeowners for any sub-components of their repository which
38+
require additional scrutiny.
39+
40+
## Runners
41+
42+
* [Do not use private runners for public repos](https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#self-hosted-runner-security)
43+
* We will use GitHub hosted runners for CI in all public repos
44+
* We will also use GitHub hosted runners for private repos unless we have a good reason that a private runner is needed
45+
46+
## Branch Protection Rules
47+
48+
* Allow Squash merges - this should be the default merge type for feature branches
49+
* Allow merge commits - this may be required for release or hotfix branches to be merged back to main
50+
* Require signed commits
51+
* Optional: merge queues may be used if merge frequency causes issues for a repository
52+
* Use branch protection rules - rulesets are currently not recognised by the engineering quality dashboard
53+
* `main` branch should be protected from deletion
54+
* Require a pull request before merging
55+
* Require approvals
56+
* Dismiss stale pull request approvals when new commits are pushed
57+
* Require review from Code Owners
58+
* Require approval of the most recent reviewable push
59+
* Require status checks to pass before merging
60+
* Require conversation resolution before merging
61+
* Require signed commits
62+
63+
## Pull requests for public repos
64+
65+
* [Pull requests from forked repos should be configured to require a maintainer to approve the workflow run for all outside contributors](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#controlling-changes-from-forks-to-workflows-in-public-repositories)
66+
* Workflow runs for PRs from forked repos run with READ_ONLY permission by default, which means they do not have access
67+
to secrets and cannot make any modifications to the base repo.
68+
69+
![fork-workflow-approval.png](assets/fork-workflow-approval.png)
70+
71+
## Bootstrapping CI/CD
72+
73+
* Public repositories should not directly invoke CD workflows, and should delegate to a private deployment repository.
74+
* [CD workflows should be granted access to an AWS deployment role via OIDC](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services)
75+
* IAM allows a new OIDC identity provider to be registered with an account
76+
* A role must be created with a trust policy allowing the GitHub repo token to assume the role.
77+
* [Example of assuming a role using OIDC in an Actions workflow](https://medium.com/@thiagosalvatore/using-terraform-to-connect-github-actions-and-aws-with-oidc-0e3d27f00123)
78+
* The set up of the necessary OIDC provider can be applied via Terraform
79+
* This step is likely to require local deployment, although it's possible we could apply the changes from inside the AWS
80+
console using cloudshell - TBD
81+
* Workflow files should be protected by the CODEOWNERS file to prevent unexpected modifications
82+
83+
## CI Workflows
84+
85+
* CI workflows should not require access to secrets
86+
* CI workflows should not require access to AWS resources
87+
* Component tests should use locally provisioned resources (docker containers or similar) or in-process test harnesses
88+
to provide mock services
89+
* Contract tests should be implemented the same way
90+
* Micro-benchmarks on the service should be implemented the same way
91+
92+
## CD Workflows
93+
94+
* Deployment workflows may be triggered by users with appropriate access to the repository
95+
* Deployment workflows should be configured to work with the GitHub environments feature
96+
* [Deployment rules should be set appropriately for the environment being deployed](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules)
97+
* Any secrets required for deployment should be set at the environment level. These will not be made available to any
98+
workflows unless the deployment is approved
99+
100+
## Post-deployment Workflows
101+
102+
* Post-deployment workflows should be triggered after CD workflows or manually as needed
103+
* These workflows should be scoped to an environment in the same way as CD workflows
104+
* For individual services the post-deployment workflows should test behaviour at the domain boundary
105+
* E.g. the test should replay a scenario and subscribe to output events to ensure the behaviour is as expected
106+
* Service level benchmarking could be performed at this point in non-production environments
107+
* Full-platform end-to-end and performance tests should live in a separate repository
108+
109+
## Artifacts and Releases
110+
111+
* Artifacts for each build should be packaged and available from the CI pipeline output
112+
* These are available for 90 days in public repos (could be extended to 400 days in private repos)
113+
* When a tag is created, a release corresponding to that tag should publish the packaged artifacts
114+
* Deployment pipelines should either be triggered from a branch or a tag
115+
* When triggered from a branch, the most recent build for that branch should be used as the source of the artifacts
116+
* When triggered from a tag, the published release artifacts should be used

docs/collections/_developers/guides/guides-index.md

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)