Harden portable Redmine CLI runtime and cache writes
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# Redmine CLI runtime
|
||||
|
||||
The live wrappers are deliberately short:
|
||||
|
||||
```bash
|
||||
bin/rcontacts-live search acme
|
||||
bin/rtickets-live search --where 'assigned_to IS NULL'
|
||||
bin/rtl search --where 'assigned_to IS NULL' # short live alias
|
||||
bin/rtd search --where 'assigned_to IS NULL' # explicit LAN/dev lane
|
||||
```
|
||||
|
||||
`--help` works without credentials. The wrappers resolve configuration independently of the current working directory and pass ordinary arguments unchanged to `redmine_contacts.py` or `redmine_tickets.py`.
|
||||
|
||||
## Diagnose configuration without API traffic
|
||||
|
||||
```bash
|
||||
bin/rcontacts-live --doctor
|
||||
bin/rtickets-live --show-config
|
||||
bin/rtl --doctor-nmi
|
||||
```
|
||||
|
||||
Diagnostics show effective paths and each setting’s source. Secrets are never printed. `network_checked: false` means readiness is local; it does not prove remote authentication.
|
||||
|
||||
## Precedence and files
|
||||
|
||||
Highest priority wins:
|
||||
|
||||
1. wrapper CLI options;
|
||||
2. exported environment;
|
||||
3. selected Redmine env file;
|
||||
4. ticket JSON/YAML `--config` values;
|
||||
5. defaults.
|
||||
|
||||
Select an env file with `--env-file PATH` or `REDMINE_ENV_FILE`. Otherwise the first existing file is used:
|
||||
|
||||
- live: checkout `.env`, legacy `bin/.env`, `~/.redmine.live`;
|
||||
- dev: checkout `.env.dev`, `bin/.env.dev`, `~/.redmine.dev`.
|
||||
|
||||
Dev never falls back to the live file. An explicitly selected missing, empty, or malformed file is an error. Files use `NAME=value` and are parsed as data; shell commands are not evaluated.
|
||||
|
||||
```text
|
||||
REDMINE_API_KEY required for API operations
|
||||
REDMINE_BASE_URL live default https://rm.ldrprep.com
|
||||
REDMINE_PROJECT default customer-service
|
||||
REDMINE_BASE_CACHE common mutable-data root
|
||||
REDMINE_CONTACTS_CACHE exact full-CRM snapshot JSON file
|
||||
REDMINE_TICKETS_CACHE exact ticket-cache directory
|
||||
REDMINE_LOCK_TIMEOUT writer wait, seconds; default 60
|
||||
REDMINE_ENV_FILE explicit env profile
|
||||
REDMINE_API_KEY_FILE file containing only the Redmine key
|
||||
```
|
||||
|
||||
NMI bridge variables (`NMI_CLI`, `NMI_ENV_FILE`, `NMI_MODE`, endpoint/credential variables) pass through to PHP. `rtl` defaults NMI to production; `rtd` defaults it to dev. `--doctor-nmi` runs the actual PHP resolver offline.
|
||||
|
||||
## Cache layout
|
||||
|
||||
`REDMINE_BASE_CACHE` chooses the common root, defaulting to checkout `cache/` live and `cache-dev/` dev.
|
||||
|
||||
- Tickets normally use `<root>/redmine_tickets/`.
|
||||
- Other endpoint/project combinations get deterministic distinct ticket directories.
|
||||
- Fresh contacts setups use `<root>/redmine_contacts/<host>_<project>.json`.
|
||||
- If historical `<root>/redmine_contacts` is already a **file** for normal live use, the wrapper preserves and uses it. There is no automatic migration.
|
||||
- Tickets’ `<ticket-cache>/contacts/` mirror is a different per-contact format, not the full contacts snapshot.
|
||||
|
||||
Exact `--cache-dir DIR` (tickets) and `--cache FILE` (contacts) win. Contacts rejects a cache directory because `redmine_contacts.py` expects one JSON file.
|
||||
|
||||
`ticket-contact` prints a shell-quoted full-CRM handoff that retains endpoint, project, env profile, API-key-file context, and cache file without putting a key in argv.
|
||||
|
||||
## Concurrency and cron
|
||||
|
||||
Writers use POSIX advisory locks around read/modify/write transactions and unique same-directory temporary files followed by atomic replacement. A process’s death releases its kernel lock; the persistent `.lock` file is only an inode anchor. A later holder removes matching temporary residue left by a killed writer.
|
||||
|
||||
Contention is visible on stderr. After `REDMINE_LOCK_TIMEOUT`, the process exits nonzero rather than making a cron failure silent.
|
||||
|
||||
```cron
|
||||
REDMINE_ENV_FILE=/etc/ldr/redmine-live.env /opt/redmine/bin/rtickets-live sync --remote-updated-since 6h --run-log --quiet
|
||||
```
|
||||
|
||||
## Completion and safety
|
||||
|
||||
```bash
|
||||
source bin/redmine-runtime-completion.bash
|
||||
```
|
||||
|
||||
This registers all four wrappers and includes the established contacts completion surface.
|
||||
|
||||
The wrappers do not weaken write safety: production ticket writes still require `--allow-prod-writes`; customer email still requires its long confirmation; NMI retains its independent mutation gates.
|
||||
Reference in New Issue
Block a user