|
1 | | -# GitHub Copilot Shell Scripting (sh) Review Instructions |
| 1 | +# GitHub Copilot Shell Scripting (sh) Review Instructions for acme.sh |
2 | 2 |
|
3 | | -## 🎯 Overall Goal |
| 3 | +## Overall Goal |
4 | 4 |
|
5 | | -Your role is to act as a rigorous yet helpful senior engineer, reviewing Shell script code (`.sh` files). Ensure the code exhibits the highest levels of robustness, security, and portability. |
| 5 | +Your role is to act as a rigorous yet helpful senior engineer, reviewing Shell script code (`.sh` files) for the [acme.sh](https://github.com/acmesh-official/acme.sh) project. Ensure the code exhibits the highest levels of robustness, security, and portability. |
6 | 6 | The review must focus on risks unique to Shell scripting, such as proper quoting, robust error handling, and the secure execution of external commands. |
7 | 7 |
|
8 | | -## 📝 Required Output Format |
| 8 | +## Required Output Format |
9 | 9 |
|
10 | | -Please adhere to the previous format: organize the feedback into a single, structured report, using the three-level marking system: |
| 10 | +Organize the feedback into a single, structured report, using the three-level marking system: |
11 | 11 |
|
12 | | -1. **🔴 Critical Issues (Must Fix Before Merge)** |
13 | | -2. **🟡 Suggestions (Improvements to Consider)** |
14 | | -3. **✅ Good Practices (Points to Commend)** |
| 12 | +1. **Critical Issues (Must Fix Before Merge)** |
| 13 | +2. **Suggestions (Improvements to Consider)** |
| 14 | +3. **Good Practices (Points to Commend)** |
15 | 15 |
|
16 | 16 | --- |
17 | 17 |
|
18 | | -## 🔍 Focus Areas and Rules for Shell |
| 18 | +## Shell Compatibility |
19 | 19 |
|
20 | | -### 1. Robustness and Error Handling |
| 20 | +- **POSIX sh only** -- all scripts must target `sh`, not `bash`. No bash-isms allowed. |
| 21 | +- **Shebang**: always use `#!/usr/bin/env sh` (not `#!/bin/sh`, not `#!/usr/bin/env bash`). |
| 22 | +- **Use `return`, never `exit`** -- scripts are sourced, not executed as subprocesses. `exit` would kill the parent shell. |
| 23 | +- **Cross-platform**: code must work on Linux, macOS, FreeBSD, Solaris, and BusyBox environments. |
21 | 24 |
|
22 | | -* **Shebang:** Check that the script starts with the correct Shebang, must be "#!/usr/bin/env sh". |
23 | | -* **Startup Options:** **(🔴 Critical)** Enforce the use of the following combination at the start of the script for safety and robustness: |
24 | | - * `set -e`: Exit immediately if a command exits with a non-zero status. |
25 | | - * `set -u`: Treat unset variables as an error and exit. |
26 | | - * `set -o pipefail`: Ensure the whole pipeline fails if any command in the pipe fails. |
27 | | -* **Exit Codes:** Ensure functions and the main script use `exit 0` for success and a non-zero exit code upon failure. |
28 | | -* **Temporary Files:** Check for the use of `mktemp` when creating temporary files to prevent race conditions and security risks. |
| 25 | +--- |
| 26 | + |
| 27 | +## Robustness and Error Handling |
| 28 | + |
| 29 | +- **(Critical)** Enforce the use of the following combination at the start of the script for safety and robustness: |
| 30 | + - `set -e`: Exit immediately if a command exits with a non-zero status. |
| 31 | + - `set -u`: Treat unset variables as an error and exit. |
| 32 | + - `set -o pipefail`: Ensure the whole pipeline fails if any command in the pipe fails. |
| 33 | +- **Always check return values** of function calls. If an error occurs, there must be a way to stop execution. |
| 34 | +- **Return 1** after `_err` messages: |
| 35 | + ```sh |
| 36 | + if [ -z "$VARIABLE" ]; then |
| 37 | + _err "VARIABLE is required" |
| 38 | + return 1 |
| 39 | + fi |
| 40 | + ``` |
| 41 | +- Check for the use of `mktemp` when creating temporary files to prevent race conditions and security risks. |
| 42 | + |
| 43 | +--- |
| 44 | + |
| 45 | +## Security and Quoting |
29 | 46 |
|
30 | | -### 2. Security and Quoting |
| 47 | +- **(Critical)** Check that all variable expansions (like `$VAR` and `$(COMMAND)`) are properly enclosed in **double quotes** (i.e., `"$VAR"` and `"$(COMMAND)"`) to prevent **Word Splitting** and **Globbing**. |
| 48 | +- **(Critical)** Find and flag any hardcoded passwords, keys, tokens, or authentication details. |
| 49 | +- Verify that all user input, command-line arguments (`$1`, `$2`, etc.), or environment variables are rigorously validated and sanitized before use. |
| 50 | +- Avoid `eval` -- warn against and suggest alternatives, as it can lead to arbitrary code execution. |
31 | 51 |
|
32 | | -* **Variable Quoting:** **(🔴 Critical)** Check that all variable expansions (like `$VAR` and `$(COMMAND)`) are properly enclosed in **double quotes** (i.e., `"$VAR"` and `"$(COMMAND)"`) to prevent **Word Splitting** and **Globbing**. |
33 | | -* **Hardcoded Secrets:** **(🔴 Critical)** Find and flag any hardcoded passwords, keys, tokens, or authentication details. |
34 | | -* **Untrusted Input:** Verify that all user input, command-line arguments (`$1`, `$2`, etc.), or environment variables are rigorously validated and sanitized before use. |
35 | | -* **Avoid `eval`:** Warn against and suggest alternatives to using `eval`, as it can lead to arbitrary code execution. |
| 52 | +--- |
36 | 53 |
|
37 | | -### 3. Readability and Maintainability |
| 54 | +## Use Built-in Helper Functions |
38 | 55 |
|
39 | | -* **Function Usage:** Recommend wrapping complex or reusable logic within clearly named functions. |
40 | | -* **Local Variables:** Check that variables inside functions are declared using the `local` keyword to avoid unintentionally modifying global state. |
41 | | -* **Naming Convention:** Variable names should use uppercase letters and underscores (e.g., `MY_VARIABLE`), or follow established project conventions. |
42 | | -* **Test Conditions:** Encourage the use of Bash's **double brackets `[[ ... ]]`** for conditional tests, as it is generally safer and more powerful (e.g., supports pattern matching and avoids Word Splitting) than single brackets `[ ... ]`. |
43 | | -* **Command Substitution:** Encourage using `$(command)` over backticks `` `command` `` for command substitution, as it is easier to nest and improves readability. |
| 56 | +Never use raw shell commands when acme.sh provides a wrapper function. This is the most critical rule for portability. |
44 | 57 |
|
45 | | -### 4. External Commands and Environment |
| 58 | +| Instead of | Use | |
| 59 | +|---|---| |
| 60 | +| `tr '[:upper:]' '[:lower:]'` | `_lower_case()` | |
| 61 | +| `head -n 1` | `_head_n 1` | |
| 62 | +| `openssl dgst` / `openssl` | `_digest()` / `_hmac()` | |
| 63 | +| `date` | `_utc_date()` with `sed`/`tr` | |
| 64 | +| `curl` / `wget` | `_get()` or `_post()` | |
| 65 | +| `sleep` | `_sleep` | |
| 66 | +| `base64` / `openssl base64` | `_base64()` | |
| 67 | +| `$(( ))` arithmetic | `_math()` | |
| 68 | +| `grep -E` / `grep -Po` | `_egrep_o()` | |
| 69 | +| `printf` | `echo` | |
| 70 | +| `idn` command | `_idn()` / `_is_idn()` | |
46 | 71 |
|
47 | | -* **`for` Loops:** Warn against patterns like `for i in $(cat file)` or `for i in $(ls)` and recommend the more robust `while IFS= read -r line` pattern for safely processing file contents or filenames that might contain spaces. |
48 | | -* **Use existing acme.sh functions whenever possible.** For example: do not use `tr '[:upper:]' '[:lower:]'`, use `_lower_case` instead. |
49 | | -* **Do not use `head -n`.** Use the `_head_n()` function instead. |
50 | | -* **Do not use `curl` or `wget`.** Use the `_post()` and `_get()` functions instead. |
| 72 | +When fixing a pattern issue, fix **all instances** in the file, not just the one highlighted. |
51 | 73 |
|
52 | 74 | --- |
53 | 75 |
|
54 | | -### 5. Review Rules for Files Under `dnsapi/`: |
| 76 | +## Forbidden External Tools |
| 77 | + |
| 78 | +Do not use these commands -- they are not portable across all target platforms: |
| 79 | + |
| 80 | +- `jq` (parse JSON with built-in string manipulation) |
| 81 | +- `grep -A` (removed throughout the project) |
| 82 | +- `grep -Po` (Perl regex not available everywhere) |
| 83 | +- `rev`, `xargs`, `iconv` |
| 84 | +- If you must depend on an external tool, check with `_exists` first: |
| 85 | + ```sh |
| 86 | + if ! _exists jq; then |
| 87 | + _err "jq is required" |
| 88 | + return 1 |
| 89 | + fi |
| 90 | + ``` |
| 91 | +- Warn against patterns like `for i in $(cat file)` or `for i in $(ls)` and recommend the more robust `while IFS= read -r line` pattern for safely processing file contents or filenames that might contain spaces. |
| 92 | + |
| 93 | +--- |
55 | 94 |
|
56 | | -* **Each file must contain a `{filename}_add` function** for adding DNS TXT records. It should use `_readaccountconf_mutable` to read the API key and `_saveaccountconf_mutable` to save it. Do not use `_saveaccountconf` or `_readaccountconf`. |
| 95 | +## Configuration Management |
57 | 96 |
|
| 97 | +Use the correct save/read functions depending on hook type: |
58 | 98 |
|
59 | | -## ❌ Things to Avoid |
| 99 | +- **DNS hooks**: `_readaccountconf_mutable` to read API keys, `_saveaccountconf_mutable` to save them. Do not use `_saveaccountconf` or `_readaccountconf`. |
| 100 | +- **Deploy hooks**: `_savedeployconf` / `_getdeployconf` |
| 101 | +- **Notification hooks**: use account conf functions. |
| 102 | +- Save operations should only happen in the correct lifecycle function (e.g., `_issue()`). |
| 103 | +- Use environment variables for all configurable values -- do not introduce hardcoded config files. |
| 104 | +- Do not clear account conf without a clear reason. |
60 | 105 |
|
61 | | -* Do not comment on purely stylistic issues like spacing or indentation, which should be handled by tools like ShellCheck or Prettier. |
62 | | -* Do not be overly verbose unless a significant issue is found. Keep feedback concise and actionable. |
| 106 | +--- |
| 107 | + |
| 108 | +## DNS API Conventions |
| 109 | + |
| 110 | +- Read the [DNS API Dev Guide](https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide) before writing a DNS plugin. |
| 111 | +- Each file under `dnsapi/` must contain a `{filename}_add` function for adding DNS TXT records. |
| 112 | +- The `_get_root()` loop counter `i` must start from `1` (not `2`) to support DNS alias mode. |
| 113 | +- The `dns_*_rm()` function must remove records **by TXT value**, not by replacing/updating. See [#1261](https://github.com/acmesh-official/acme.sh/issues/1261). |
| 114 | +- Preserve the `dns_*_info` metadata variable block in each DNS script header. |
| 115 | + |
| 116 | +--- |
| 117 | + |
| 118 | +## Variable Naming |
| 119 | + |
| 120 | +- Use CamelCase with provider prefix: `KINGHOST_Username` (not `KINGHOST_username`). |
| 121 | +- Variable names should use uppercase letters and underscores (e.g., `MY_VARIABLE`), or follow established project conventions. |
| 122 | +- Avoid confusingly similar names. Prefer one variable with comma-separated values over multiple variables (e.g., `CZ_Zones` with comma support instead of separate `CZ_Zone` and `CZ_Zones`). |
| 123 | +- Do not define variables with the same name in different scopes. |
| 124 | +- Variables inside functions should be declared using the `local` keyword to avoid unintentionally modifying global state. |
| 125 | + |
| 126 | +--- |
63 | 127 |
|
| 128 | +## Code Style |
64 | 129 |
|
| 130 | +- Use `shfmt` for formatting -- CI enforces it. |
| 131 | +- Reduce indentation where possible. |
| 132 | +- Single space, not double spaces. |
| 133 | +- No trailing semicolons after `return` statements. |
| 134 | +- Add a newline at the end of every file. |
| 135 | +- Use `$(command)` over backticks `` `command` `` for command substitution. |
65 | 136 |
|
| 137 | +--- |
| 138 | + |
| 139 | +## Simplicity |
| 140 | + |
| 141 | +- Prefer hardcoded sensible defaults over unnecessary configuration variables (e.g., use `3600` for TTL instead of a `DESEC_TTL` variable). |
| 142 | +- Reject over-engineered solutions. If it can be done in one line, do it in one line. |
| 143 | +- Follow existing patterns in the codebase -- new hooks should look like existing hooks. |
| 144 | +- Respect user choices: do not `chmod` files that already exist; the user's permissions take priority. |
| 145 | + |
| 146 | +--- |
| 147 | + |
| 148 | +## Documentation Requirements |
| 149 | + |
| 150 | +Before a PR can be merged, the following documentation must be provided: |
| 151 | + |
| 152 | +- **Wiki page**: add or update the relevant page: |
| 153 | + - DNS APIs: [dnsapi](https://github.com/acmesh-official/acme.sh/wiki/dnsapi) or [dnsapi2](https://github.com/acmesh-official/acme.sh/wiki/dnsapi2) |
| 154 | + - Deploy hooks: [deployhooks](https://github.com/acmesh-official/acme.sh/wiki/deployhooks) |
| 155 | + - Notification hooks: [notify](https://github.com/acmesh-official/acme.sh/wiki/notify) |
| 156 | + - Options: [Options-and-Params](https://github.com/acmesh-official/acme.sh/wiki/Options-and-Params) |
| 157 | +- **In-code usage**: add usage examples in the help text of `acme.sh` itself. |
| 158 | +- **README**: add website URLs for new DNS providers. |
| 159 | + |
| 160 | +--- |
| 161 | + |
| 162 | +## CI and Merge Hygiene |
| 163 | + |
| 164 | +- All CI checks must pass before merge. |
| 165 | +- Rebase to the latest `dev` branch frequently -- do not use merge commits. |
| 166 | +- Enable GitHub Actions on your fork to catch errors early. |
| 167 | +- Run the [DNS API Test](https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Test) workflow for DNS plugins. |
| 168 | +- For Docker changes, ensure the Dockerfile includes any required dependencies. |
| 169 | + |
| 170 | +--- |
| 171 | + |
| 172 | +## Debug Logging |
| 173 | + |
| 174 | +- Use `_debug2` (not `_debug3` or other levels) unless there is a specific reason for a different level. |
| 175 | + |
| 176 | +--- |
66 | 177 |
|
| 178 | +## Things to Avoid in Reviews |
67 | 179 |
|
| 180 | +- Do not comment on purely stylistic issues like spacing or indentation, which should be handled by tools like ShellCheck or `shfmt`. |
| 181 | +- Do not be overly verbose unless a significant issue is found. Keep feedback concise and actionable. |
0 commit comments