exec allowlist: the three occ commands that add what a Nextclouds upgrade leaves missing in the database
ci / check (push) Successful in 2m43s
ci / publish (push) Successful in 39s

For the post-upgrade check (owner, 2026-09-20): php occ db:add-missing-indices, db:add-missing-columns and
db:add-missing-primary-keys, as www-data in nextcloud/app, exact argv. Nothing runs them until the owner sets a post-upgrade
executor for nextcloud in Apps. A test holds the committed file to the rule schema and to this exact list. No new dependency.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
homelab-updaterandClaude Sonnet 5 committed 2026-09-20 02:04:12 +02:00
1 parent e879bfd3ae
commit e2cb6e3e6b
3 files changed
+59 -2

No files matched your search

+32 -1
View File
@@ -1 +1,32 @@
[]
[
{
"project": "nextcloud",
"service": "app",
"user": "www-data",
"argv": [
"php",
"occ",
"db:add-missing-indices"
]
},
{
"project": "nextcloud",
"service": "app",
"user": "www-data",
"argv": [
"php",
"occ",
"db:add-missing-columns"
]
},
{
"project": "nextcloud",
"service": "app",
"user": "www-data",
"argv": [
"php",
"occ",
"db:add-missing-primary-keys"
]
}
]
+1 -1
View File
@@ -62,7 +62,7 @@ cd /opt/homelab/compose/homelab-upgrade && TAG=manual docker compose up -d
Dwa ustawienia w Apps → aplikacja, oba domyślnie wyłączone (wtedy łańcuch jest jak dawniej):
- **Release notes source**: `github:owner/repo` (releases repozytorium) albo URL strony/pliku. Z nim skok powyżej progu `auto` trafia najpierw do modelu (`release_notes`), a właściciel widzi w decyzji jego ocenę. Nextcloud: `github:nextcloud/server`.
- **Post-upgrade check executor**: `sonnet` / `opus` = po udanym `verify` model sprawdza, czy aktualizacja wymaga czynności poinstalacyjnych. Model wykona tylko to, co dopuszcza `config/agent-exec.json` (dokładne komendy, bez wildcardów); reszta trafia do właściciela jako STOP `migration_required`. Lista jest dziś pusta, więc dopóki właściciel nie doda komend, ten krok tylko wypisze, co zrobić ręcznie.
- **Post-upgrade check executor**: `sonnet` / `opus` = po udanym `verify` model sprawdza, czy aktualizacja wymaga czynności poinstalacyjnych. Model wykona tylko to, co dopuszcza `config/agent-exec.json` (dokładne komendy, bez wildcardów); reszta trafia do właściciela jako STOP `migration_required`. Dziś lista ma tylko trzy komendy Nextclouda (`php occ db:add-missing-indices`, `db:add-missing-columns`, `db:add-missing-primary-keys`, użytkownik `www-data`, usługa `app`); dla pozostałych aplikacji ten krok tylko wypisze, co zrobić ręcznie.
Schemat bazy przechodzi na v8 (kolumny `release_notes_source`, `post_upgrade_executor`); starszy obraz jej nie otworzy, więc przed wdrożeniem kopia `queue.sqlite*`.
+26
View File
@@ -0,0 +1,26 @@
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { describe, expect, it } from 'vitest';
import { AgentExecRules } from '../domain/executor-api.ts';
// The allowlist the model's `hl exec` is held to is committed with the code; a typo in it must fail here, not on VM103.
const rules = AgentExecRules.parse(JSON.parse(readFileSync(join(import.meta.dirname, '../../config/agent-exec.json'), 'utf8')));
describe('config/agent-exec.json', () => {
it('holds exact commands only: a user, a full argv, no shell and no wildcards', () => {
for (const rule of rules) {
expect(rule.user).not.toBeNull();
expect(rule.argv.join(' ')).not.toMatch(/[*?]/);
expect(rule.argv[0]).not.toMatch(/(^|\/)(ba|da|z)?sh$/);
}
});
it('lets a model add what an upgrade of Nextcloud leaves missing in the database, and nothing else', () => {
expect(rules.filter((rule) => rule.project === 'nextcloud').map((rule) => rule.argv.join(' '))).toEqual([
'php occ db:add-missing-indices',
'php occ db:add-missing-columns',
'php occ db:add-missing-primary-keys',
]);
expect(rules.every((rule) => rule.project === 'nextcloud' && rule.service === 'app' && rule.user === 'www-data')).toBe(true);
});
});