Q2 Create OS user incomex on VPS Report S178 Fix 11
Q2 — Create OS user incomex on VPS — Report
Ngày chạy: 2026-04-17 06:50 UTC+7
Phiên: S178 Fix 11 (Q2 phụ, ngoài 8 Phase Đ43)
Agent: Claude CLI qua SSH contabo
VPS: vmi3080463 (38.242.240.89)
CHECKPOINT
Đã đọc: Đ41 VPS-SSOT + report Phase 2 Issue 2.
1. PRE-STATE
$ getent passwd 1001 → (empty, UID 1001 UNNAMED)
$ getent group 1001 → (empty, GID 1001 UNNAMED)
$ getent passwd incomex → (empty, không tồn tại)
$ getent group incomex → (empty, không tồn tại)
$ grep ^incomex: /etc/passwd /etc/group → (no match, không có user/group tên incomex khác)
$ awk -F: '$3>=999 && $3<=1010' /etc/group
systemd-journal:x:999: (không đụng 1001)
$ stat -c "%U:%G" /opt/incomex/dot/bin /opt/incomex/context-pack*
/opt/incomex/dot/bin UNKNOWN:UNKNOWN (tức 1001:1001)
/opt/incomex/context-pack UNKNOWN:UNKNOWN
/opt/incomex/context-pack.tmp UNKNOWN:UNKNOWN
/opt/incomex/context-pack-staging UNKNOWN:UNKNOWN
PRE-STATE xác nhận UID/GID 1001 chưa được user/group nào chiếm → an toàn tạo user incomex gắn vào UID/GID đã có.
Phát hiện phụ: 2 file .sh Phase 2 (dot-dieu43-fs-init.sh, dot-dieu43-fs-verify.sh) đang root:root (do tôi ssh as root để tạo file), lệch với pattern /opt/incomex/dot/bin/ (1001:1001). Đã fix chown incomex:incomex sau khi useradd để khớp pattern — là "file chưa khớp UID 1001" đúng trường hợp §7 cho phép.
2. QUYẾT ĐỊNH THIẾT KẾ
Chọn useradd -u 1001 -g incomex -M -s /usr/sbin/nologin -c "...":
| Flag | Giá trị | Lý do |
|---|---|---|
-u 1001 |
UID cố định | Match UID UNNAMED hiện có trên /opt/incomex/ — mục tiêu chính của Q2 |
-g incomex |
Primary group | Dùng group vừa tạo (GID 1001) — tránh useradd tự sinh private group GID khác |
-M |
Không tạo home dir | incomex là service/app account, không phải user đăng nhập. /opt/incomex/ là app directory (không phải HOME — đã ghi trong prompt §4.4). Home /home/incomex ghi trong /etc/passwd để pass validator nhưng KHÔNG tạo trên FS (verified: ls /home/incomex → No such file). |
-s /usr/sbin/nologin |
Không shell login | Ngăn interactive login (service account, không cần ai SSH vào bằng user này). An toàn hơn mặc định /bin/sh. |
-c "Incomex app service account" |
GECOS comment | Ghi rõ vai trò trong /etc/passwd để ai đọc cũng hiểu. |
Thứ tự an toàn: groupadd trước → useradd -g incomex — đảm bảo primary group có sẵn, tránh useradd tự sinh private group với GID khác 1001.
3. LỆNH ĐÃ CHẠY (nguyên văn)
groupadd -g 1001 incomex
useradd -u 1001 -g incomex -M -s /usr/sbin/nologin \
-c "Incomex app service account" incomex
# Fix ownership 2 Phase 2 scripts (thừa hưởng Phase 2 side-effect):
chown incomex:incomex /opt/incomex/dot/bin/dot-dieu43-fs-init.sh
chown incomex:incomex /opt/incomex/dot/bin/dot-dieu43-fs-verify.sh
3 lệnh trên, không thêm gì khác. Không sudo/wheel, không password, không SSH key, không bulk chown.
4. POST-STATE: 7 TIÊU CHÍ
| # | Tiêu chí | Expected | Actual | PASS? |
|---|---|---|---|---|
| C1 | id incomex UID/GID 1001 |
uid=1001(incomex) gid=1001(incomex) | uid=1001(incomex) gid=1001(incomex) groups=1001(incomex) |
PASS |
| C2 | getent passwd incomex có entry |
non-empty | incomex:x:1001:1001:Incomex app service account:/home/incomex:/usr/sbin/nologin |
PASS |
| C3 | getent group incomex có entry |
non-empty | incomex:x:1001: |
PASS |
| C4 | Phase 2 scripts hiển thị tên owner | incomex:incomex | -rwxr-xr-x 1 incomex incomex 4966 ... dot-dieu43-fs-init.sh / -rwxr-xr-x 1 incomex incomex 3853 ... dot-dieu43-fs-verify.sh |
PASS |
| C5 | context-pack* 3 folder hiển thị tên |
incomex:incomex | /opt/incomex/context-pack incomex:incomex mode=755 / .tmp incomex:incomex mode=755 / -staging incomex:incomex mode=755 |
PASS |
| C6 | dot-dieu43-fs-verify.sh exit 0 |
0 | 0 (3/3 PASS) | PASS |
| C7 | dot-dieu43-fs-init.sh idempotent |
0 + 0 diff | exit 0, IDEMPOTENT: OK (0 diff) |
PASS |
Verify output C6 (nguyên văn):
[INFO] dot-dieu43-fs-verify v1.0.0
[INFO] Ownership reference: /opt/incomex/dot/bin (uid:gid = 1001:1001) / mode 755
[PASS] /opt/incomex/context-pack (owner=1001:1001 mode=755)
[PASS] /opt/incomex/context-pack.tmp (owner=1001:1001 mode=755)
[PASS] /opt/incomex/context-pack-staging (owner=1001:1001 mode=755)
[PASS] Phase 2 filesystem verified — 3/3 folder OK
(script vẫn in UID:GID dạng số 1001:1001 vì dùng stat -c '%u:%g' — là intended behavior, không thay đổi. Muốn hiển thị %U:%G tên user thì phải sửa script, ngoài scope Q2.)
Bonus observation: /opt/incomex/dot vẫn root:root (app-level owner), /opt/incomex/dot/bin là incomex:incomex (nơi DOT script sống). Pattern này hợp lý: root sở hữu container dir, incomex sở hữu vùng code runtime.
5. BẤT THƯỜNG PHÁT SINH
Không có sự cố.
Một điểm nhỏ để Desktop biết: /etc/passwd ghi home là /home/incomex nhưng thư mục đó KHÔNG tồn tại trên FS (vì -M). Với service account dùng nologin, đây là pattern chuẩn — hệ thống không bao giờ thực sự cần home dir này. Nếu về sau có process nào cố cd ~ khi chạy as incomex, sẽ fail — nhưng không có use case đó.
Nếu Desktop muốn "sạch" hoàn toàn, có thể usermod -d /nonexistent incomex để đổi home thành /nonexistent (convention cho service account). Không bắt buộc.
6. KẾT LUẬN
Q2 PASS — 7/7 tiêu chí.
User OS incomex:incomex (UID 1001, GID 1001) đã tồn tại trên VPS. 4 luật Đ33/Đ35/Đ41/Đ43 giờ khớp thực tế VPS khi nói "owner incomex:incomex". Phase 2 Đ43 vẫn PASS sau thay đổi. Phase 1 Đ43 (PG-only) không bị ảnh hưởng.
Tác động rộng
- Các file/folder đang UID 1001 trên toàn hệ thống (không chỉ
/opt/incomex/) sẽ tự động hiển thị tênincomex:incomextrongls -la,stat, v.v. - Scripts Phase 2 giờ owner khớp pattern folder parent (
incomex:incomexcả 2). - Sẵn sàng Phase 6 (install cron dưới user
incomex— tính năng của Phase 6, không phải Q2).
KHÔNG làm gì rộng hơn (theo §2 M4 + §7)
- Không tạo user khác (không
postgres/directusOS user) - Không bulk chown
/opt/incomex/(tự hiển thị tên khi lookup UID) - Không sudo/wheel/admin group
- Không password/SSH key
- Không shell login (nologin)
Report by Claude CLI — S178 Fix 11 Q2 — 2026-04-17