dumbtv
dumbtv가 ADB로 Fire TV에서 광고·추적·업데이트 알림을 제거, 루트·앱 변경 없이, 무료 오픈소스
무료 오픈소스 AI가 보안 알림을 읽고 중요한 것만 알려주며, 실행 전에 확인하고 로컬에서 동작합니다
Free and open source. An AI reads the security alerts your tools raise, tells you which ones matter, and asks before it does anything. Runs on your own computer.
보안TypeScript · HTMLGitHub @S2K7x온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A security console in two halves, in one web application:
• the SOC handles what has already happened — an alert is already an incident;
• VulnPipe handles what is about to happen — a flaw in the code, before it ships.
→ menater.vercel.app — what the product is, what
it refuses to do, and what it does not do yet, with screenshots of a running
install. Read that first if you are here to find out what this is.
This project is built to run in Docker
That is the normal way to install it, not a deployment option. Three
commands, on any host:
Then.README 전문 보기 ↗A security console in two halves, in one web application:
→ menater.vercel.app — what the product is, what it refuses to do, and what it does not do yet, with screenshots of a running install. Read that first if you are here to find out what this is.
That is the normal way to install it, not a deployment option. Three commands, on any host:
cp .env.example .env # fill in the two passwords
docker compose up -d --build
Then http://localhost:4400.
Nothing else is required. No Node to install, no Postgres to configure, no SQL schema to apply by hand, no workflow engine to install, no third machine. The stack is self-contained and behaves the same on a Mac, on Linux, or on a Raspberry Pi.
| Service | Role | Port |
|---|---|---|
console | Interface, API, and the workflow engine | 4400 |
postgres | Run log, audit, deduplication, variables, tuning rules | internal |
vulnpipe | Code vulnerability analysis | internal |
One port is published. The database and the analyser are reachable only
from the compose network: the console relays /api/vulnpipe/* to the second,
and nobody talks to the database directly. One origin, one lock — a second
entry point would be a lock protecting half the application.
up: the four things to setThe stack comes up in three minutes and triages nothing. That is not a fault — each of these is a choice the console refuses to make for you. The checklist at the top of Settings tracks all four, and disappears when they are done.
| # | What | Where | If you skip it |
|---|---|---|---|
| 1 | Shared secret | Settings → Ingestion | The endpoint stays closed whatever mode you pick |
| 2 | Open the door — mode Primary | Settings → Ingestion | Every alert is refused |
| 3 | Model key (OpenRouter) | Settings → Credentials | Every alert takes the fail-safe verdict: needs_human, confidence 0. Nothing is lost, but nothing is triaged |
| 4 | A log source | Settings → Ingestion → Sources | No alerts arrive |
Slack and the enrichment keys (Shodan, AbuseIPDB, VirusTotal) are optional. A missing enrichment source is shown as unavailable rather than filled in, and the model has to name it in its reasoning.
On the ingestion mode. There are two:
Closed, the default, which refuses everything, andOpen, where the built-in engine handles alerts. A shared secret is required either way — an empty one keeps the door closed rather than opening it to everyone.
Alerts arrive at POST /api/ingest/<source>. The route decides which mapping
applies — never the payload, so a sender cannot claim to be something else.
Settings → Ingestion generates the endpoint, the install commands and the
config block, using the address you reached the console on.
One file to copy, one block to paste — see integrations/wazuh/README.md.
scp integrations/wazuh/custom-menater root@wazuh-manager:/var/ossec/integrations/
chmod 750 /var/ossec/integrations/custom-menater
chown root:wazuh /var/ossec/integrations/custom-menater
systemctl restart wazuh-manager
The script maps nothing: it forwards the alert exactly as Wazuh wrote it, and the console does the translation. An integrator that maps fields turns "add a log source" into "maintain a parser on a production security appliance", unversioned and invisible from the console.
| Tier | Fields | Rule |
|---|---|---|
| Identity | alert_id, rule_name, severity, timestamp, raw_log | Required. Missing means rejected, and the rejection names them |
| Observables | source_ip, dest_ip, user, host, process, file_path, url | Optional. Absent stays absent — never invented, never an empty string |
| Extensions | everything else | Kept whole. Nothing your tool sends is discarded |
Most real detections have no destination address. That is why dest_ip is
optional: rejecting the alert over it would replace it with nothing.
The Rules tab is where a team teaches the console what is normal here — the authorised scanner, the backup window, the deployment account. Without it an honest console alerts on everything, and one that alerts on everything stops being read.
A rule can close an alert as known, suppress it temporarily, change its severity, or demand a human. It can never trigger an action: no rule effect reaches the action catalogue.
Three things the console refuses, each matching an exception shape that is known to go wrong:
allow keyed on one identity field alone — attackers use
legitimate addresses and accounts, so that is a hole shaped like an intrusion;suppress with no expiry — it is temporary by definition;Eight templates ship disabled and unowned, all written as conjunctions. The dry-run panel answers which rule would match this alert without touching the pipeline.
Settings → Health → inject a test alert offers nine scenarios, one per path rather than per story: no destination, with a hash, low severity, malformed, duplicate, and so on. Each creates a real case; the malformed one is rejected on purpose, and the duplicate one exercises deduplication.
docker compose --profile tunnel up -d # exposure to the Internet
tunnel opens a Cloudflare tunnel to the alert endpoint. Only enable it
after setting a shared secret in Settings → Ingestion: without one the
endpoint stays closed, but the tunnel would already be open.
They are off by default because a service you do not know you started is a service you are not watching — and one of the two opens a door to the Internet.
sql/ in order — audit with hash chaining, error log,
engine run log, deduplication, metrics function, tuning rules;Data lives in named volumes: it survives docker compose down and
up --build. To start over — including the database: docker compose down -v.
Docker is still the normal mode. To work on the code with hot reload:
cd dashboard && npm install
npm run dev # API (4400) + code analysis (4319) + Vite interface (5174)
npm test # 1219 tests, 1 skipped (the one needing a database)
See dashboard/README.md.
The Postgres store tests are skipped without a database — and say so. To run them against the Docker stack:
MENATER_TEST_PG=postgres://menater:<password>@localhost:5432/menater_test npm test
site/ is a static page describing the project, deployed on Vercel at
menater.vercel.app. It is not part of the
console and the Docker stack does not serve it: nothing in docker-compose.yml
knows it exists.
| File | Holds |
|---|---|
site/page.src.html | The front page. The short version — plain words, no jargon, ~670 rendered words |
site/docs.src.html | The documentation. Sixteen sections behind a sticky sidebar, ~4 800 words |
site/shared.css | One stylesheet, inlined into every output |
site/partials/ | Header, footer and script, shared by both pages |
site/i18n/fr.json | The French, against the same keys |
site/shots/ | Seven screenshots of a running install, and captions.json beside them |
site/build.sh | Writes the six outputs from those sources |
site/check.cjs | Measures the built site in a browser: contrast, overflow, anchors, script errors |
cd site && ./build.sh # after editing a source, a caption or a catalogue
Two pages, and they answer different questions. / is for someone deciding
in ten seconds whether this is for them; /docs is for someone who already
decided and wants the specifics. The split is why the front page could drop from
3 147 words to 670 without deleting anything: what used to be folded on it now
has a page of its own, with a sidebar and its own vocabulary section.
| Built | Served at |
|---|---|
site/index.html | / |
site/docs/index.html | /docs |
site/fr/index.html | /fr |
site/fr/docs/index.html | /fr/docs |
site/page.html · site/page.fr.html | nowhere — the front page with its screenshots inlined, for a host that blocks external images |
Two languages, and the URL is the whole state. Each page is a static file
with its own lang attribute and hreflang pair; the switcher is two links
that carry your anchor across and keep you on the page you were reading. No
cookie, no header sniffing, no redirect — a link somebody shares opens in the
language they shared it in, and the page never arrives in one language and
repaints in another. A key present on one side only fails the build, naming
it: the typed-catalogue rule the console applies to console.ts, applied to a
page.
Contrast is measured, not looked at. check.cjs drives a real browser over
both pages, both languages and all six palettes — 648 checks — plus horizontal
overflow from 320 px, every in-page anchor, and script errors. It needs
Playwright; it exits non-zero on a failure, so it can gate a change.
Root Directory is site, and that is the only setting. Vercel's importer
scans the repository for a framework, finds dashboard/ — a Vite app — and
offers to build the console instead, pre-filling seventeen environment
variables from the root .env.example along the way. Pointing it at site/
removes the question: that folder has no package.json and no .env.example,
so there is nothing to detect and nothing to ask for.
| Setting | Value |
|---|---|
| Root Directory | site |
| Framework Preset | Other |
| Build / Install Command | leave empty |
| Environment Variables | none — the page is static and reads nothing |
site/vercel.json carries the rest: cleanUrls — which is what makes
docs/index.html answer at /docs — long-lived caching on the screenshots,
which never change under their own name, a no-cache rule on everything else so
a deploy is visible immediately, and the three headers a public page should not
be without. site/.vercelignore keeps the generator, the browser check and the
inlined variants off the public host.
Every screenshot is a real screen, taken against docker compose up with
alerts injected through the real pipeline — no mockups, and none of them is a
console with nothing in it. The captions say what state the install was in,
including that no model key was configured, which is why every verdict on them
reads fallback verdict. A page about a product that refuses to fill a gap with
a default cannot itself show an invented one.
| File | Contents |
|---|---|
| CLAUDE.md | Architecture, design rules, and the traps that cost time |
| ROADMAP.md | What is delivered, what is coming, and why — one list for both halves |
| dashboard/README.md | The console in detail |
| integrations/wazuh/README.md | Connecting Wazuh, end to end |
| VulnPipe/README.md | The code analysis engine |
The Guide tab documents every feature from inside the application, which is where the question usually gets asked.
No irreversible action without explicit human approval. The action
catalogue is closed: isolate_host_temporary (with a TTL and automatic
revert), ticket, escalate, auto_close. Nothing else is implementable,
not even behind an approval — and no tuning rule can reach it.
Silence is never consent. An approval that expires executes nothing: it
escalates. And missing configuration cannot enable execution — shadow mode is
on by default, and only the exact string false turns it off.