Move inline code examples out of normative contracts
identifier-normalization, no-hardcoded-vendors, vendor-installer-verification, and build-version-display follow the go-database split: rules in contract.md, snippets in README.md. Routed contract reads get cheaper; examples stay available on demand. Lint now also rejects stale kit/patterns references. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
29
rules/patterns/build-version-display/README.md
Normal file
29
rules/patterns/build-version-display/README.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Build Version Display Pattern Notes
|
||||||
|
|
||||||
|
This file keeps examples. The normative rules live in `contract.md`.
|
||||||
|
|
||||||
|
## Frontend (JS/TS build tools)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// vite.config.ts / webpack.config.js
|
||||||
|
define: {
|
||||||
|
__APP_VERSION__: JSON.stringify(process.env.APP_VERSION ?? "dev"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Footer component
|
||||||
|
<footer>v{__APP_VERSION__}</footer>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Go (server-rendered HTML)
|
||||||
|
|
||||||
|
```go
|
||||||
|
// main.go
|
||||||
|
var Version = "dev"
|
||||||
|
|
||||||
|
// Build: go build -ldflags "-X main.Version=1.4.2"
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- base template -->
|
||||||
|
<footer>v{{ .Version }}</footer>
|
||||||
|
```
|
||||||
@@ -1,18 +1,13 @@
|
|||||||
# Contract: Build Version Display
|
# Contract: Build Version Display
|
||||||
|
|
||||||
Version: 1.0
|
Version: 1.1
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
Every web application must display the current build version in the page footer so that users and support staff can identify exactly which version is running.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Rule
|
## Rule
|
||||||
|
|
||||||
The build version **must** be visible in the footer on every page of the web application.
|
The build version **must** be visible in the footer on every page of the web application,
|
||||||
|
so users and support staff can identify exactly which version is running.
|
||||||
|
|
||||||
---
|
See `README.md` for implementation snippets.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
@@ -22,42 +17,6 @@ The build version **must** be visible in the footer on every page of the web app
|
|||||||
- Format: any human-readable string that uniquely identifies the build — a semver tag, a git commit SHA, or a combination (e.g. `1.4.2`, `1.4.2-abc1234`, `abc1234`).
|
- Format: any human-readable string that uniquely identifies the build — a semver tag, a git commit SHA, or a combination (e.g. `1.4.2`, `1.4.2-abc1234`, `abc1234`).
|
||||||
- The version text must be legible but visually subordinate — use a muted color and small font size so it does not compete with page content.
|
- The version text must be legible but visually subordinate — use a muted color and small font size so it does not compete with page content.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Recommended implementation
|
|
||||||
|
|
||||||
**Frontend (JS/TS build tools)**
|
|
||||||
|
|
||||||
Expose the version through an environment variable at build time and reference it in the footer component:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// vite.config.ts / webpack.config.js
|
|
||||||
define: {
|
|
||||||
__APP_VERSION__: JSON.stringify(process.env.APP_VERSION ?? "dev"),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Footer component
|
|
||||||
<footer>v{__APP_VERSION__}</footer>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Go (server-rendered HTML)**
|
|
||||||
|
|
||||||
Inject via `-ldflags` at build time and pass to the template:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// main.go
|
|
||||||
var Version = "dev"
|
|
||||||
|
|
||||||
// Build: go build -ldflags "-X main.Version=1.4.2"
|
|
||||||
```
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!-- base template -->
|
|
||||||
<footer>v{{ .Version }}</footer>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What is NOT allowed
|
## What is NOT allowed
|
||||||
|
|
||||||
- Omitting the version from any page, including error pages.
|
- Omitting the version from any page, including error pages.
|
||||||
|
|||||||
54
rules/patterns/identifier-normalization/README.md
Normal file
54
rules/patterns/identifier-normalization/README.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Identifier Normalization Pattern Notes
|
||||||
|
|
||||||
|
This file keeps examples. The normative rules live in `contract.md`.
|
||||||
|
|
||||||
|
## Go — сравнение
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func SameIdentifier(a, b string) bool {
|
||||||
|
return strings.EqualFold(a, b)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Go — дедупликация
|
||||||
|
|
||||||
|
```go
|
||||||
|
func deduplicateBySerial(items []Device) []Device {
|
||||||
|
seen := make(map[string]struct{})
|
||||||
|
result := items[:0]
|
||||||
|
for _, item := range items {
|
||||||
|
key := strings.ToLower(item.SerialNumber)
|
||||||
|
if _, exists := seen[key]; !exists {
|
||||||
|
seen[key] = struct{}{}
|
||||||
|
result = append(result, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## SQL — поиск и уникальность
|
||||||
|
|
||||||
|
Поиск:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT * FROM devices WHERE LOWER(serial_number) = LOWER(?);
|
||||||
|
```
|
||||||
|
|
||||||
|
Уникальный индекс (MySQL / MariaDB):
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Collation ci обеспечивает case-insensitive уникальность
|
||||||
|
ALTER TABLE devices MODIFY serial_number VARCHAR(255)
|
||||||
|
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
ALTER TABLE devices ADD UNIQUE INDEX uniq_serial (serial_number);
|
||||||
|
```
|
||||||
|
|
||||||
|
SQLite:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE UNIQUE INDEX uniq_serial ON devices (LOWER(serial_number));
|
||||||
|
```
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
# Contract: Identifier Normalization
|
# Contract: Identifier Normalization
|
||||||
|
|
||||||
Version: 1.0
|
Version: 1.1
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
Правила хранения и сравнения идентификаторов оборудования:
|
Правила хранения и сравнения идентификаторов оборудования:
|
||||||
серийные номера, вендоры, версии прошивок, партномера, артикулы.
|
серийные номера, вендоры, версии прошивок, партномера, артикулы.
|
||||||
|
|
||||||
---
|
See `README.md` for Go and SQL examples.
|
||||||
|
|
||||||
## Правило
|
## Правило
|
||||||
|
|
||||||
@@ -17,11 +17,8 @@ Version: 1.0
|
|||||||
```
|
```
|
||||||
Пришло: "SN-001-ABC" → хранится: "SN-001-ABC"
|
Пришло: "SN-001-ABC" → хранится: "SN-001-ABC"
|
||||||
Пришло: "sn-001-abc" → это тот же объект, не дубликат
|
Пришло: "sn-001-abc" → это тот же объект, не дубликат
|
||||||
Пришло: "Sn-001-Abc" → то же самое
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Применяется к полям
|
## Применяется к полям
|
||||||
|
|
||||||
- Серийный номер (`serial_number`, `serial`)
|
- Серийный номер (`serial_number`, `serial`)
|
||||||
@@ -30,61 +27,13 @@ Version: 1.0
|
|||||||
- Партномер (`part_number`, `part_no`)
|
- Партномер (`part_number`, `part_no`)
|
||||||
- Артикул (`article`, `sku`)
|
- Артикул (`article`, `sku`)
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Реализация
|
## Реализация
|
||||||
|
|
||||||
### Go — сравнение
|
- Go: сравнение только через `strings.EqualFold`, никогда `==`.
|
||||||
|
- Go: ключ дедупликации в map — `strings.ToLower(value)`; сам объект хранит оригинал.
|
||||||
```go
|
- SQL-поиск: `WHERE LOWER(col) = LOWER(?)`.
|
||||||
import "strings"
|
- Уникальность: MySQL/MariaDB — case-insensitive collation (`utf8mb4_unicode_ci`) +
|
||||||
|
unique index; SQLite — `CREATE UNIQUE INDEX ... ON t (LOWER(col))`.
|
||||||
func SameIdentifier(a, b string) bool {
|
|
||||||
return strings.EqualFold(a, b)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Go — дедупликация
|
|
||||||
|
|
||||||
```go
|
|
||||||
func deduplicateBySerial(items []Device) []Device {
|
|
||||||
seen := make(map[string]struct{})
|
|
||||||
result := items[:0]
|
|
||||||
for _, item := range items {
|
|
||||||
key := strings.ToLower(item.SerialNumber)
|
|
||||||
if _, exists := seen[key]; !exists {
|
|
||||||
seen[key] = struct{}{}
|
|
||||||
result = append(result, item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Ключ в map — всегда `strings.ToLower(value)`. Сам объект сохраняется с оригинальным значением.
|
|
||||||
|
|
||||||
### SQL — поиск и уникальность
|
|
||||||
|
|
||||||
Поиск:
|
|
||||||
```sql
|
|
||||||
SELECT * FROM devices WHERE LOWER(serial_number) = LOWER(?);
|
|
||||||
```
|
|
||||||
|
|
||||||
Уникальный индекс (MySQL / MariaDB):
|
|
||||||
```sql
|
|
||||||
-- Collation ci обеспечивает case-insensitive уникальность
|
|
||||||
ALTER TABLE devices MODIFY serial_number VARCHAR(255)
|
|
||||||
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
|
|
||||||
ALTER TABLE devices ADD UNIQUE INDEX uniq_serial (serial_number);
|
|
||||||
```
|
|
||||||
|
|
||||||
SQLite:
|
|
||||||
```sql
|
|
||||||
CREATE UNIQUE INDEX uniq_serial ON devices (LOWER(serial_number));
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Что не делать
|
## Что не делать
|
||||||
|
|
||||||
|
|||||||
42
rules/patterns/no-hardcoded-vendors/README.md
Normal file
42
rules/patterns/no-hardcoded-vendors/README.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# No Hardcoded Vendors Pattern Notes
|
||||||
|
|
||||||
|
This file keeps examples. The normative rules live in `contract.md`.
|
||||||
|
|
||||||
|
## Запрещено
|
||||||
|
|
||||||
|
```go
|
||||||
|
if device.Vendor == "Dell" { ... }
|
||||||
|
if strings.Contains(model, "PowerEdge") { ... }
|
||||||
|
switch vendor {
|
||||||
|
case "HP", "HPE", "Hewlett Packard": ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Запрещено — список вендоров в коде
|
||||||
|
var knownVendors = []string{"Dell", "HP", "Cisco", "Lenovo"}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Правильно
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Смотрим на возможности объекта, не на имя вендора
|
||||||
|
if device.HasIPMI { ... }
|
||||||
|
if device.ParserType == "redfish" { ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
Маппинг в конфиге:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# config.yaml
|
||||||
|
vendor_parsers:
|
||||||
|
dell: redfish
|
||||||
|
hp: ilo
|
||||||
|
cisco: ucs
|
||||||
|
```
|
||||||
|
|
||||||
|
Маппинг в БД:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT parser_type FROM vendor_registry WHERE LOWER(vendor) = LOWER(?);
|
||||||
|
```
|
||||||
@@ -1,64 +1,23 @@
|
|||||||
# Contract: No Hardcoded Vendors or Models
|
# Contract: No Hardcoded Vendors or Models
|
||||||
|
|
||||||
Version: 1.0
|
Version: 1.1
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
Запрет на хардкод названий вендоров, моделей и партномеров в коде.
|
Запрет на хардкод названий вендоров, моделей и партномеров в коде.
|
||||||
|
|
||||||
---
|
See `README.md` for code examples.
|
||||||
|
|
||||||
## Правило
|
## Правило
|
||||||
|
|
||||||
Названия вендоров, моделей, серий оборудования и партномеров **не появляются в коде**.
|
Названия вендоров, моделей, серий оборудования и партномеров **не появляются в коде**.
|
||||||
Они приходят из данных: БД, конфига, входного документа, справочника.
|
Они приходят из данных: БД, конфига, входного документа, справочника.
|
||||||
|
|
||||||
---
|
- Запрещены сравнения и switch по имени вендора (`if device.Vendor == "Dell"`) и
|
||||||
|
списки вендоров в коде (`var knownVendors = []string{...}`).
|
||||||
## Что запрещено
|
- Логика определяется по полям из данных (`device.HasIPMI`, `device.ParserType`),
|
||||||
|
не по названию вендора.
|
||||||
```go
|
- Если нужен маппинг вендор → поведение, он живёт в конфиге или справочной таблице БД.
|
||||||
// Запрещено
|
|
||||||
if device.Vendor == "Dell" { ... }
|
|
||||||
if strings.Contains(model, "PowerEdge") { ... }
|
|
||||||
switch vendor {
|
|
||||||
case "HP", "HPE", "Hewlett Packard": ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Запрещено — список вендоров в коде
|
|
||||||
var knownVendors = []string{"Dell", "HP", "Cisco", "Lenovo"}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Что делать вместо
|
|
||||||
|
|
||||||
Логика определяется по полям из данных, не по названию вендора:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Правильно — смотрим на возможности объекта, не на имя вендора
|
|
||||||
if device.HasIPMI { ... }
|
|
||||||
if device.ParserType == "redfish" { ... }
|
|
||||||
```
|
|
||||||
|
|
||||||
Если нужен маппинг — он живёт в конфиге или справочной таблице БД, не в коде:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# config.yaml
|
|
||||||
vendor_parsers:
|
|
||||||
dell: redfish
|
|
||||||
hp: ilo
|
|
||||||
cisco: ucs
|
|
||||||
```
|
|
||||||
|
|
||||||
```sql
|
|
||||||
-- справочник в БД
|
|
||||||
SELECT parser_type FROM vendor_registry WHERE LOWER(vendor) = LOWER(?);
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Исключения
|
## Исключения
|
||||||
|
|
||||||
@@ -70,8 +29,6 @@ SELECT parser_type FROM vendor_registry WHERE LOWER(vendor) = LOWER(?);
|
|||||||
|
|
||||||
В этих местах название вендора — идентификатор модуля, не условие в логике.
|
В этих местах название вендора — идентификатор модуля, не условие в логике.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Почему
|
## Почему
|
||||||
|
|
||||||
Хардкод вендора делает код хрупким: новый вендор требует правок в коде, а не в данных.
|
Хардкод вендора делает код хрупким: новый вендор требует правок в коде, а не в данных.
|
||||||
|
|||||||
46
rules/patterns/vendor-installer-verification/README.md
Normal file
46
rules/patterns/vendor-installer-verification/README.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Vendor Installer Verification Pattern Notes
|
||||||
|
|
||||||
|
This file keeps examples. The normative rules live in `contract.md`.
|
||||||
|
|
||||||
|
## Download Order
|
||||||
|
|
||||||
|
```sh
|
||||||
|
BASE_URL="https://vendor.example.com/downloads/${VERSION}"
|
||||||
|
BIN_FILE="/var/cache/vendor-${VERSION}.run"
|
||||||
|
SHA_FILE="/var/cache/vendor-${VERSION}.run.sha256sum"
|
||||||
|
|
||||||
|
# 1. Download checksum first
|
||||||
|
wget -q -O "$SHA_FILE" "${BASE_URL}/vendor-${VERSION}.run.sha256sum"
|
||||||
|
|
||||||
|
# 2. Download installer
|
||||||
|
wget --show-progress -O "$BIN_FILE" "${BASE_URL}/vendor-${VERSION}.run"
|
||||||
|
|
||||||
|
# 3. Verify
|
||||||
|
cd /var/cache
|
||||||
|
sha256sum -c "$SHA_FILE" || { echo "ERROR: sha256 mismatch"; rm -f "$BIN_FILE"; exit 1; }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cache with Verification
|
||||||
|
|
||||||
|
```sh
|
||||||
|
verify_cached() {
|
||||||
|
[ -s "$SHA_FILE" ] || return 1 # sha256 file missing or empty
|
||||||
|
[ -s "$BIN_FILE" ] || return 1 # binary missing or empty
|
||||||
|
cd "$(dirname "$BIN_FILE")"
|
||||||
|
sha256sum -c "$SHA_FILE" --status 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! verify_cached; then
|
||||||
|
rm -f "$BIN_FILE" "$SHA_FILE"
|
||||||
|
# ... download and verify
|
||||||
|
else
|
||||||
|
echo "verified from cache"
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
## Version Validation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl -sIL "https://vendor.example.com/downloads/${VERSION}/installer.run" \
|
||||||
|
| grep -i 'http/\|content-length'
|
||||||
|
```
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Contract: Vendor Installer Verification
|
# Contract: Vendor Installer Verification
|
||||||
|
|
||||||
Version: 1.0
|
Version: 1.1
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
@@ -8,75 +8,19 @@ Rules for downloading and verifying proprietary vendor installers (`.run`, `.exe
|
|||||||
where the vendor publishes a checksum alongside the binary.
|
where the vendor publishes a checksum alongside the binary.
|
||||||
Applies to: NVIDIA drivers, vendor CLI tools, firmware packages.
|
Applies to: NVIDIA drivers, vendor CLI tools, firmware packages.
|
||||||
|
|
||||||
---
|
See `README.md` for shell snippets.
|
||||||
|
|
||||||
## Download Order
|
|
||||||
|
|
||||||
Always download the checksum file **before** the installer:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
BASE_URL="https://vendor.example.com/downloads/${VERSION}"
|
|
||||||
BIN_FILE="/var/cache/vendor-${VERSION}.run"
|
|
||||||
SHA_FILE="/var/cache/vendor-${VERSION}.run.sha256sum"
|
|
||||||
|
|
||||||
# 1. Download checksum first
|
|
||||||
wget -q -O "$SHA_FILE" "${BASE_URL}/vendor-${VERSION}.run.sha256sum"
|
|
||||||
|
|
||||||
# 2. Download installer
|
|
||||||
wget --show-progress -O "$BIN_FILE" "${BASE_URL}/vendor-${VERSION}.run"
|
|
||||||
|
|
||||||
# 3. Verify
|
|
||||||
cd /var/cache
|
|
||||||
sha256sum -c "$SHA_FILE" || { echo "ERROR: sha256 mismatch"; rm -f "$BIN_FILE"; exit 1; }
|
|
||||||
```
|
|
||||||
|
|
||||||
Reason: if the download is interrupted, you have the expected checksum to verify against on retry.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Cache with Verification
|
|
||||||
|
|
||||||
Never assume a cached file is valid — a previous download may have been interrupted (0-byte file):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
verify_cached() {
|
|
||||||
[ -s "$SHA_FILE" ] || return 1 # sha256 file missing or empty
|
|
||||||
[ -s "$BIN_FILE" ] || return 1 # binary missing or empty
|
|
||||||
cd "$(dirname "$BIN_FILE")"
|
|
||||||
sha256sum -c "$SHA_FILE" --status 2>/dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
if ! verify_cached; then
|
|
||||||
rm -f "$BIN_FILE" "$SHA_FILE"
|
|
||||||
# ... download and verify
|
|
||||||
else
|
|
||||||
echo "verified from cache"
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
**Never check only for file existence.** Check that the file is non-empty (`-s`) AND passes checksum.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Version Validation
|
|
||||||
|
|
||||||
Before writing build scripts, verify the version URL actually exists:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
curl -sIL "https://vendor.example.com/downloads/${VERSION}/installer.run" \
|
|
||||||
| grep -i 'http/\|content-length'
|
|
||||||
```
|
|
||||||
|
|
||||||
A `404` or `content-length: 0` means the version does not exist on that CDN.
|
|
||||||
Vendor version numbering may have gaps (e.g. NVIDIA skips minor versions on some CDNs).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Rules
|
## Rules
|
||||||
|
|
||||||
- Download checksum before installer — never after.
|
- Download the checksum file **before** the installer — never after. If the download is
|
||||||
|
interrupted, you still have the expected checksum to verify against on retry.
|
||||||
- Verify checksum before extracting or executing.
|
- Verify checksum before extracting or executing.
|
||||||
- On mismatch: delete the file, exit with error. Never proceed with a bad installer.
|
- On mismatch: delete the file, exit with error. Never proceed with a bad installer.
|
||||||
|
- Never assume a cached file is valid — a previous download may have been interrupted.
|
||||||
|
**Never check only for file existence**: the file must be non-empty (`-s`) AND pass checksum.
|
||||||
- Cache by `version` + any secondary key (e.g. kernel version for compiled modules).
|
- Cache by `version` + any secondary key (e.g. kernel version for compiled modules).
|
||||||
|
- Before writing build scripts, verify the version URL actually exists (`curl -sIL`).
|
||||||
|
A `404` or `content-length: 0` means the version is absent on that CDN; vendor version
|
||||||
|
numbering may have gaps.
|
||||||
- Never commit installer files to git — always download at build time.
|
- Never commit installer files to git — always download at build time.
|
||||||
- Log the expected hash when downloading so failures are diagnosable.
|
- Log the expected hash when downloading so failures are diagnosable.
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ for ref in $(grep -o 'bible/rules/patterns/[a-z-]*/contract\.md' AGENT-BOOTSTRAP
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# 3. No machine-local absolute paths in committed markdown.
|
# 3. No machine-local absolute paths or stale path prefixes in committed markdown.
|
||||||
if grep -rn '/Users/' --include='*.md' . --exclude-dir=.git; then
|
if grep -rn '/Users/\|kit/patterns' --include='*.md' . --exclude-dir=.git; then
|
||||||
echo "FAIL: machine-local absolute paths found (see above)"
|
echo "FAIL: machine-local absolute paths or stale kit/patterns references found (see above)"
|
||||||
fail=1
|
fail=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user