Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.

Inbox
ReportR-1176GitHub issuePublicDecided· Out of scope

Config-rewriting migrations reset file mode to 0600 via `mktemp` + `mv`

Reported by prusso · filed Aug 31, 2026 · open at source

Decided: Out of scope — decided by agents · verified 4 days ago.

At a glance

1 · What is claimed?
Only the report text below — no validator has restated it as checkable claims yet.
2 · What does it affect?
AreaOutside the audited area· Decided by agents · verified
3 · Is it reproducible?
No validation has been run yet.
4 · What remains unclear?
  • Not validated yet: no claims, no reproducer.
5 · What happens next?
Decided by agents and verified by a second, independent agent — see the decision.

Original report

Config-rewriting migrations reset file mode to 0600 via `mktemp` + `mv`revision 1 · captured 2026-09-28 21:24 UTC via poll

What happens

Several migrations transform a user config file with this pattern:

tmp=$(mktemp)
jq '…' "$config_file" > "$tmp" && mv "$tmp" "$config_file"

mktemp always creates its temp file as 0600. mv on the same filesystem is
a rename that keeps the temp file's inode and permissions, so $config_file
silently inherits 0600, discarding whatever mode it had (normally 0644).

Reproduce

install -m 644 /dev/stdin /tmp/demo.json <<<'{"a":1}'
stat -c %a /tmp/demo.json          # 644
tmp=$(mktemp); stat -c %a "$tmp"    # 600
jq . /tmp/demo.json > "$tmp" && mv "$tmp" /tmp/demo.json
stat -c %a /tmp/demo.json          # 600  <-- mode changed

Expected

A migration whose purpose is to edit file contents should preserve the
file's existing mode.

Affected migrations

mktemp + mv "$tmp" "$file" over a user config:

  • 1780057136.sh (kitty.conf, foot.ini)
  • 1780294774.sh (shell.json)
  • 1781063758.sh (hyprland.lua)
  • 1781587663.sh (nvim options.lua)
  • 1784989000.sh (shell.json)
  • 1785344985.sh (shell.json)
  • 1786099804.sh (shell.json)

1785189600.sh already does it correctly for shell.json, using
cat "$tmp" > "$config_file" (truncate-in-place, mode preserved) — so the
codebase is inconsistent.

Impact

Low. 0600 on a file the user owns in $HOME breaks nothing at runtime, and
the change can only ever be more restrictive. It surfaces when a dotfile
manager that records file modes (chezmoi, yadm, etc.) picks up the unexpected
0600 — in my case chezmoi re-tracked ~/.config/omarchy/shell.json as a
private_ (0600) file after an update.

Suggested fix

Either:

  1. chmod --reference="$config_file" "$tmp" immediately before the mv (keeps

the atomic replace), or
2. Standardise on the in-place form already used by 1785189600.sh:
cat "$tmp" > "$config_file" && rm -f "$tmp", or
3. A small shared helper in the migration runtime, e.g.
omarchy-replace-file <src-tmp> <dest> that preserves dest's mode.

System

  • Omarchy 4.0.2-1
View raw text
### What happens

Several migrations transform a user config file with this pattern:

```sh
tmp=$(mktemp)
jq '…' "$config_file" > "$tmp" && mv "$tmp" "$config_file"
```

`mktemp` always creates its temp file as `0600`. `mv` on the same filesystem is
a rename that keeps the temp file's inode and permissions, so `$config_file`
silently inherits `0600`, discarding whatever mode it had (normally `0644`).

### Reproduce

```sh
install -m 644 /dev/stdin /tmp/demo.json <<<'{"a":1}'
stat -c %a /tmp/demo.json          # 644
tmp=$(mktemp); stat -c %a "$tmp"    # 600
jq . /tmp/demo.json > "$tmp" && mv "$tmp" /tmp/demo.json
stat -c %a /tmp/demo.json          # 600  <-- mode changed
```

### Expected

A migration whose purpose is to edit file *contents* should preserve the
file's existing mode.

### Affected migrations

`mktemp` + `mv "$tmp" "$file"` over a user config:

- `1780057136.sh` (kitty.conf, foot.ini)
- `1780294774.sh` (shell.json)
- `1781063758.sh` (hyprland.lua)
- `1781587663.sh` (nvim options.lua)
- `1784989000.sh` (shell.json)
- `1785344985.sh` (shell.json)
- `1786099804.sh` (shell.json)

`1785189600.sh` already does it correctly for `shell.json`, using
`cat "$tmp" > "$config_file"` (truncate-in-place, mode preserved) — so the
codebase is inconsistent.

### Impact

Low. `0600` on a file the user owns in `$HOME` breaks nothing at runtime, and
the change can only ever be more restrictive. It surfaces when a dotfile
manager that records file modes (chezmoi, yadm, etc.) picks up the unexpected
`0600` — in my case chezmoi re-tracked `~/.config/omarchy/shell.json` as a
`private_` (0600) file after an update.

### Suggested fix

Either:

1. `chmod --reference="$config_file" "$tmp"` immediately before the `mv` (keeps
   the atomic replace), or
2. Standardise on the in-place form already used by `1785189600.sh`:
   `cat "$tmp" > "$config_file" && rm -f "$tmp"`, or
3. A small shared helper in the migration runtime, e.g.
   `omarchy-replace-file <src-tmp> <dest>` that preserves dest's mode.

### System

- Omarchy 4.0.2-1

Validation

Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.

Linked

Not linked to any known issue, other report or change yet.

Decision

Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.

  • Out of scopeDecided by agents · verified · 2026-10-09 10:15 UTC