@topy-ai/maggie 0.7.59 → 0.7.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-zh-TW.md +1 -1
- package/README.md +5 -3
- package/bundled-tools/clis/maggie_security_report.py +72 -0
- package/package.json +1 -1
package/README-zh-TW.md
CHANGED
|
@@ -143,7 +143,7 @@ structure drift 或重複 treatment product 時 fail closed。
|
|
|
143
143
|
deployment、memory、feedback 和 MaggieDash。內容先 draft/review,外部寫入、
|
|
144
144
|
publish 與 production deployment 需要明確確認。
|
|
145
145
|
|
|
146
|
-
目前 npm 版本為 `0.7.
|
|
146
|
+
目前 npm 版本為 `0.7.60`,包含 fix-plan、public-check、Maggie Security、batch 31 排程 agent routines、報告收件匣與無人值守 agent 限制、PHP runtime 盤點與主機鎖、pull 網站改寫、query 點子與社群佇列檢查,batch 30 MaggieDash 先裝核心、release privacy gate、feedback 備援、社群連結與圖片檢查、大量頁面產生與 app 檢查,batch 29 預約規則、部署、app QA、助理與社群功能,以及 batch 28 產品 app、assistant tools、mobile、product release、skills catalog 與 bridge host 功能、batch 26、27 feedback 修正與 idempotent `maggie update`與 Booking email-template 合約/CLI validator 同步。本版完成 2026-09-24 booking feedback batch:Calendar grid/free-slot entry 與 host modal focus-restoration evidence。本版新增 Starter marketplace provisioning plan;本版完成 feedback batches 22、23:加入 declarative browser interaction evidence、design markup/style/content-key gate、compiler source anchoring、entity double-escape protection、`update --help` read-only、noindex hypothetical indexability、可過期 baseline acknowledgement、DOM-only link extraction regression,以及 MaggieDash 0.2.10 的 content override、短期 browser session、CDN-safe public-session cache contracts。authentication 和 isolated dev server 仍由 host 負責。`maggie-booking` workflow、傳統 email/password、Stripe、Resend、public booking flow 及既有安全邊界維持不變;provider-bound video generation 與 transactional delivery 仍記錄在 issue #39,前一批延後功能仍在 issue #38,不會直接成為 active memory。0.7.33 記錄並審查一筆更正回饋;確認 0.7.32 已正確處理 batch index,沒有修改已驗證的 shared behavior。0.7.32 加入 feedback 一基索引支援、MaggieDash panel 的 source/freshness/error evidence、Consent Mode 與實際 write/no-op reconciliation、SEO baseline recapture、sitemap origin rebasing、content-diff scope、migration ledger reconciliation、deployment credential preflight、release provenance/runtime preflight、icon release gate、opt-in blog auto-publish gate,以及 least-privilege VPS deployer。也修復 top-level `maggie feedback` dispatcher parity。0.7.31 加入 update 差異摘要、atomic installer copy、subset install manifest merge,以及 inventory drift 時 doctor non-zero。0.7.30 補上 feedback tracking issue closeout gate 與 batch 14/15 audit ledger。0.7.29 修正 npm package landing page 使用英文 README;0.7.28 加入 versioned Gemini model policy、明確 fallback 與 provenance、bundled-first CLI
|
|
147
147
|
dispatch、`maggie --version`、feedback batch review 聚合與重複偵測、marketplace enrichment evidence、booking
|
|
148
148
|
worker/resolver evidence,以及 read-only migration preflight。它也包含 host-owned mobile app surface contract、signed-in
|
|
149
149
|
camera-state QA、直接 Astro route resolution、correlated feedback batch,以及
|
package/README.md
CHANGED
|
@@ -89,7 +89,9 @@ Maggie keeps the existing project foundation and asks for decisions before
|
|
|
89
89
|
shared routes, analytics, or publishing boundaries change. The current
|
|
90
90
|
package ships 23 installable skills and a local-first MaggieDash foundation.
|
|
91
91
|
|
|
92
|
-
This package is `0.7.
|
|
92
|
+
This package is `0.7.60`. `maggie security fix-plan` now emits **runnable** nginx fixes: http-context directives (TLS protocols, `server_tokens`) go into a global `conf.d` drop-in, and server-context ones (deny dotfiles, `proxy_hide_header`) into a snippet file applied with a backed-up, `nginx -t`-validated, auto-reverting `include`.
|
|
93
|
+
|
|
94
|
+
The 0.7.59 release made `maggie security host-audit` (the deep
|
|
93
95
|
lynis audit over SSH) robust on hosts where a storage test can stall: lynis runs
|
|
94
96
|
in its own process group under a watchdog, and the bundled profile skips the ZFS
|
|
95
97
|
storage/filesystem tests that hang, so the audit completes instead of timing out.
|
|
@@ -856,8 +858,8 @@ artifact schemas.
|
|
|
856
858
|
Recommended upgrade sequence for the current release:
|
|
857
859
|
|
|
858
860
|
```bash
|
|
859
|
-
npx @topy-ai/maggie@0.7.
|
|
860
|
-
npx @topy-ai/maggie@0.7.
|
|
861
|
+
npx @topy-ai/maggie@0.7.60 update --scope project --project . --force
|
|
862
|
+
npx @topy-ai/maggie@0.7.60 cleanup --scope project --project .
|
|
861
863
|
```
|
|
862
864
|
|
|
863
865
|
Maintainers should pass npm credentials through the repository helper, never
|
|
@@ -15,6 +15,7 @@ from __future__ import annotations
|
|
|
15
15
|
import argparse
|
|
16
16
|
import json
|
|
17
17
|
import re
|
|
18
|
+
import shlex
|
|
18
19
|
from pathlib import Path
|
|
19
20
|
|
|
20
21
|
import maggie_security_core as core
|
|
@@ -557,6 +558,71 @@ def fix_commands(action: dict) -> tuple[list[str], list[tuple[str, str]], list[s
|
|
|
557
558
|
return commands, snippets, todos
|
|
558
559
|
|
|
559
560
|
|
|
561
|
+
# nginx directives valid in the http{} context can be dropped into conf.d; the
|
|
562
|
+
# rest (location/proxy/add_header) must live in a server{} block.
|
|
563
|
+
NGINX_HTTP_DIRECTIVES = {"ssl_protocols", "ssl_ciphers", "ssl_prefer_server_ciphers", "ssl_ecdh_curve",
|
|
564
|
+
"ssl_session_tickets", "ssl_session_timeout", "ssl_dhparam", "server_tokens"}
|
|
565
|
+
NGINX_FILE_RE = re.compile(r"(/etc/nginx/[\w./-]+\.conf)")
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
def nginx_fix_block(actions: list[dict]) -> tuple[list[str], list[str]]:
|
|
569
|
+
"""Runnable nginx fixes: a global drop-in for http-context directives, and a
|
|
570
|
+
snippet file + a guarded, reversible `include` for server-context ones."""
|
|
571
|
+
http_dirs: list[tuple[str, dict]] = []
|
|
572
|
+
server_by_file: dict[str, list[str]] = {}
|
|
573
|
+
manual: list[dict] = []
|
|
574
|
+
for action in actions:
|
|
575
|
+
rem = action["lead"].get("remediation") or {}
|
|
576
|
+
snippets = [s.get("text", "").strip() for s in (rem.get("snippets") or []) if s.get("text")]
|
|
577
|
+
if not snippets:
|
|
578
|
+
manual.append(action)
|
|
579
|
+
continue
|
|
580
|
+
tp = (action["lead"].get("target") or {}).get("path") or ""
|
|
581
|
+
match = NGINX_FILE_RE.search(tp) or NGINX_FILE_RE.search(action["lead"].get("title", ""))
|
|
582
|
+
vfile = match.group(1) if match else None
|
|
583
|
+
for text in snippets:
|
|
584
|
+
name = text.split()[0] if text.split() else ""
|
|
585
|
+
if name in NGINX_HTTP_DIRECTIVES:
|
|
586
|
+
http_dirs.append((text, action))
|
|
587
|
+
elif vfile:
|
|
588
|
+
server_by_file.setdefault(vfile, [])
|
|
589
|
+
if text not in server_by_file[vfile]:
|
|
590
|
+
server_by_file[vfile].append(text)
|
|
591
|
+
else:
|
|
592
|
+
manual.append(action)
|
|
593
|
+
sh: list[str] = []
|
|
594
|
+
md: list[str] = []
|
|
595
|
+
if http_dirs:
|
|
596
|
+
directives = list(dict.fromkeys(d for d, _ in http_dirs))
|
|
597
|
+
fixes = "; ".join(dict.fromkeys(a["title"] for _, a in http_dirs))
|
|
598
|
+
body = "".join(d + "\n" for d in directives)
|
|
599
|
+
sh += [f"# Global TLS/hardening — fixes: {fixes}",
|
|
600
|
+
f"printf %s {shlex.quote(body)} | sudo tee /etc/nginx/conf.d/00-maggie-hardening.conf >/dev/null",
|
|
601
|
+
"sudo nginx -t && sudo systemctl reload nginx", ""]
|
|
602
|
+
md.append("- **nginx global hardening** → drop-in `/etc/nginx/conf.d/00-maggie-hardening.conf`: "
|
|
603
|
+
+ ", ".join(f"`{d}`" for d in directives))
|
|
604
|
+
for vfile, directives in server_by_file.items():
|
|
605
|
+
stem = re.sub(r"[^\w.-]", "_", re.sub(r"\.conf$", "", vfile.rsplit("/", 1)[-1]))
|
|
606
|
+
snip = f"/etc/nginx/snippets/maggie-{stem}.conf"
|
|
607
|
+
heredoc = "\n".join(directives)
|
|
608
|
+
sh += [f"# Harden {vfile} (backs up, validates, auto-reverts on error)",
|
|
609
|
+
f"sudo tee {snip} >/dev/null <<'MAGGIE_SNIP'",
|
|
610
|
+
heredoc,
|
|
611
|
+
"MAGGIE_SNIP",
|
|
612
|
+
f"sudo cp -a {shlex.quote(vfile)} {shlex.quote(vfile + '.maggie.bak')}",
|
|
613
|
+
f"sudo sed -i -E '/^[[:space:]]*server[[:space:]]*\\{{[[:space:]]*$/a\\ include {snip};' {shlex.quote(vfile)}",
|
|
614
|
+
f"sudo nginx -t && sudo systemctl reload nginx || {{ echo 'nginx test failed — reverting'; "
|
|
615
|
+
f"sudo cp -a {shlex.quote(vfile + '.maggie.bak')} {shlex.quote(vfile)}; sudo systemctl reload nginx; }}", ""]
|
|
616
|
+
md.append(f"- **nginx vhost hardening** (`{vfile}` via `{snip}` + guarded include): "
|
|
617
|
+
+ ", ".join(f"`{d}`" for d in directives))
|
|
618
|
+
for action in manual:
|
|
619
|
+
rem = action["lead"].get("remediation") or {}
|
|
620
|
+
sh += [f"# [{action['priority']}] {action['title']} — {action['why']}",
|
|
621
|
+
f"# TODO (manual): {rem.get('summary') or action['how']}", ""]
|
|
622
|
+
md.append(f"- **{action['title']}** — {rem.get('summary') or action['how']} _(manual)_")
|
|
623
|
+
return sh, md
|
|
624
|
+
|
|
625
|
+
|
|
560
626
|
def fix_plan(ctx: core.Context) -> dict:
|
|
561
627
|
args = ctx.args
|
|
562
628
|
since = resolve_since(ctx, args.since)
|
|
@@ -597,6 +663,12 @@ def fix_plan(ctx: core.Context) -> dict:
|
|
|
597
663
|
continue
|
|
598
664
|
sh += [f"# =================== {label} ===================", f"# {note}", ""]
|
|
599
665
|
md += [f"## {label}", f"_{note}_", ""]
|
|
666
|
+
if key == "web-server":
|
|
667
|
+
block_sh, block_md = nginx_fix_block(items)
|
|
668
|
+
sh += block_sh
|
|
669
|
+
md += block_md
|
|
670
|
+
total += len(items)
|
|
671
|
+
continue
|
|
600
672
|
for action in items:
|
|
601
673
|
total += 1
|
|
602
674
|
sh.append(f"# [{action['priority']}] {action['title']} — {action['why']}")
|