lacs-project / lacs-project/sysknife

Story coverage map: 64 Ubuntu and cross-family actions have no story, clustered into takeable pieces

Open
#233 2 comments 0 reactions 1 assignee Claimed by @bferanmi806-sketch View on GitHub
claimed enhancement help wanted medium
Dominant language
Rust
Stars
12
Forks
19
Avg merge
18h 57m
Merged PRs (30d)
116

Description

64 of the 164 Ubuntu-and-cross-family actions are named by no story at all, and 98 of them are named by no story that runs on Ubuntu. This issue is the map, so the work can be taken one cluster at a time.

## Derivation

```bash
python3 - <<'PY'
import re, glob
from collections import Counter
rows = re.findall(r'^\| `([A-Za-z0-9_]+)` \|.*?\| (All|Ubuntu|Fedora) \|',
open('docs/action-reference.md').read(), re.M)
U = {n for n, d in rows if d in ('All', 'Ubuntu')}
named = set()
for f in glob.glob('tests/e2e/stories/*.sh'):
named |= set(re.findall(r'"([A-Za-z0-9_]+)"', open(f, errors='replace').read()))
ub = [f for f in glob.glob('tests/e2e/stories/*.sh')
if re.search(r'^# Story \d+ \([^)]*ubuntu[^)]*\)', open(f, errors='replace').read(), re.M)]
named_ub = set()
for f in ub:
named_ub |= set(re.findall(r'"([A-Za-z0-9_]+)"', open(f, errors='replace').read()))
print('|U| =', len(U), 'uncovered =', len(U - named), 'not on ubuntu =', len(U - named_ub))
PY
|U| = 164 uncovered = 64 not on ubuntu = 98
```

Catalogue split: 189 tabled rows, `All` 97, `Ubuntu` 67, `Fedora` 25. 79 story files carry an `ubuntu` header tag.

Two honest caveats. This counts an action as covered when its name appears as a quoted literal anywhere in a story, which over-counts: `ConfigureWifi`, `GrubSetKargs` and `SetLocale` appear only inside "must not confuse with" comments. And 34 Ubuntu-and-`All` actions are covered only by stories 1 to 54, the atomic family, which no recorded Ubuntu run includes, so `AptListUpgradable`, a Debian-only action, has its sole coverage in a Fedora-family story.

## Clusters, each one a reasonable PR

Ubuntu-family exclusive, highest priority:

- **fail2ban** (4): tracked separately in #219
- **GRUB kargs** (1): `GrubSetKargs`

Cross-family (`All`):

- **sysctl and auditd** (5): `GetSysctl`, `SetSysctl`, `GetAuditRules`, `AddAuditRule`, `RemoveAuditRule`
- **PAM policy and lockout** (6): `GetPasswordAging`, `SetPasswordAging`, `SetPasswordPolicy`, `SetAccountLockout`, `LockUserAccount`, `UnlockUserAccount`
- **Scoped sudoers.d** (3): `GetSudoGrants`, `GrantSudoAccess`, `RevokeSudoAccess`
- **Groups** (2): `CreateGroup`, `DeleteGroup`
- **Mounts and swap** (5): `GetMounts`, `AddMount`, `RemoveMount`, `AddSwap`, `RemoveSwap`
- **LVM** (4): `GetLvmReport`, `CreateLogicalVolume`, `ExtendLogicalVolume`, `CreateLvSnapshot`
- **Log management** (5): `GetLogrotateStatus`, `ConfigureLogRotation`, `RemoveLogRotation`, `ConfigureRemoteSyslog`, `RemoveRemoteSyslog`
- **Journald and diagnostics** (3): `GetJournalLog`, `VacuumJournal`, `CollectDiagnostics`
- **Container lifecycle** (4): `CreateContainer`, `StartContainer`, `StopContainer`, `RemoveContainer`
- **Flatpak remotes and info** (4): `ListFlatpakRemotes`, `AddFlatpakRemote`, `RemoveFlatpakRemote`, `GetFlatpakAppInfo`
- **Toolbox** (2): `ListToolboxes`, `RemoveToolbox`
- **certbot and ACME** (3): `GetCertificates`, `ObtainCertificate`, `RenewCertificates`
- **DNS, wifi, sockets** (4): `ResolvectlStatus`, `ResolvectlSetDns`, `ConfigureWifi`, `GetListeningPorts`
- **systemd extras** (4): `UnmaskService`, `CreateScheduledJob`, `GetServiceResourceLimits`, `SetServiceResourceLimits`
- **Time and locale** (3): `GetDateTime`, `SetNtp`, `SetLocale`
- **Singletons** (2): `SetSshdOption`, `SignalProcess`

## How to take one

Pick a cluster, write one story per action, and record on Ubuntu the way the current 79 run:

```bash
UBUNTU_RELEASE=noble ./tests/e2e/ubuntu-vm.sh
```

Then commit the cassette and its replay twin so the suite still runs offline. `run-stories.sh` accepts story numbers, so you can record only yours. Any of the seven `*_API_KEY` variables the runner recognises works; no credentials are needed from the maintainer.

The header decides the family and a wrong one fails silently, so use `# Story (ubuntu, ): ` and check that `bash tests/e2e/run-stories.sh --metadata` puts your story in the `ubuntu` family. Next free id is 134.

Start with a read-only cluster if this is your first story. `GetMounts`, `GetSysctl` and `GetListeningPorts` need no approval receipt and exercise the whole chain.

## Worth fixing alongside

Nothing compares the story set against the action catalogue, which is why this drifted unnoticed. The derivation above is small enough to become a gate, and it would keep the number in #229 honest at the same time.

## Difficulty

`medium` per cluster. The harness and the pattern exist; the work is writing intents and recording a clean pass.

## Getting started

[CONTRIBUTING.md](https://github.com/lacs-project/sysknife/blob/main/CONTRIBUTING.md) has the build and test commands, and its E2E section covers the VM harness. No CLA and no copyright waiver. The project is MIT.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.