Repository navigation
Releases: dreamforgestudiollc/EMET
Releases · dreamforgestudiollc/EMET
Release list
EMET 0.2.4
A small fix release, plus EMET's first npm package and a public website.
What changed
- Board edits work again. If a session started with no open drops to handle, EMET forgot to save that empty list, so it later refused board edits as if the list had never loaded. It now saves the empty list. If the list really does fail to load, board edits are still refused, as before.
- EMET is on npm as
@dreamforgestudiollc/emet. Run it withnpx -y @dreamforgestudiollc/emet, or install it withnpm install -g @dreamforgestudiollc/emet, which gives you theemetcommand. The package only includes what's needed to run the server: no tests, scripts, or.env. The example settings file it ships is the safe public one. It listens only on your own machine, uses generic source tags, and leaves the sign-in passphrase unset. - MCP Registry manifest.
server.jsondescribes EMET for the Official MCP Registry asio.github.dreamforgestudiollc/emet. - Website. EMET has a site at https://dreamforgestudiollc.github.io/EMET/. Only this repository's
mainbranch can publish it. - Windows fix. On Windows, module files sometimes failed to open because of a doubled drive letter (
C:\C:\...). They open correctly now. - Glama listing.
glama.jsonnames the maintainer for the Glama directory.
Upgrading
Nothing changes in the data or the settings. You can deploy 0.2.4 directly over 0.2.3.
Full details are in CHANGELOG.md.
EMET 0.2.3
The security fixes from the October audit, recall that ranks by how well an entry matches and keeps ended entries visible, and public wording that matches the code. Read the 0.2.3 checklist in docs/DEPLOY.md before upgrading: every host tag must be listed in EMET_SOURCE_TAGS, a cloud-scheduled- tag is refused, and an HTTP client whose token has no source tag signs in again once.
Security
- The client-metadata fetch connects to the public address it already checked. A second DNS answer cannot move that connection onto a private, loopback, link-local, or metadata address. A redirect is still refused.
- That address check uses the parsed bits of the address. The whole link-local range
fe80::/10is refused, includingfe90::andfebf::. The same check refuses loopback, private, unique-local, unspecified, multicast, IPv4-mapped and IPv4-compatible addresses, NAT6464:ff9b::/96, and carrier-grade NAT. An unreachable pinned address rejects the fetch and does not crash the process. - Every HTTP response sends
X-Content-Type-Options: nosniff,X-Frame-Options: DENY,Referrer-Policy: no-referrer, and HSTS. The consent page keeps its own content security policy. save_transcriptno longer reads a file path. The caller passes the exchanges, each field is capped, and the whole request is capped. The server does not read the disk for a transcript.- An invite code, an authorization code, and a refresh token can be spent once. A second redeem does not create a second person. Inside a short grace window a repeated refresh returns the replacement already issued; any other reuse revokes that whole sign-in.
- A board edit or restore runs only when the session has a verified drop list from
emet_session_open. An append does not open that session. No write may shrink a document below half of its largest size in the last 24 hours. That window is a floor on cuts, not a fading of memory. - A refusal does not publish the list of source tags, and a
cloud-scheduled-prefix is not a registered tag. Over HTTP the source tag is the one bound at approval. Stdio stamps one local subject, and the 20-drop cap is one bucket for the whole local process. - Setup, guest invites, and member codes are the owner's. A guest invite is read-only. Opening a session, and a status check that probes the write path, need write access. The probe removes its own document and leaves the collection. An HTTP token with no scopes is not the owner. The consent page shows the scopes it is granting.
- A governed write that names a session stops when the session record cannot be read. Nothing is written.
- The client-metadata fetch refuses loopback, private, link-local, and metadata addresses, and it is rate limited. Tool rate limits are per person and client. The HTTP body limit is 256kb, and the server trusts one proxy hop.
- The consent page sends a content security policy, denies framing, and sends HSTS. Error details are not attached on HTTP, including a rate-limit response. The audit log is redacted the same way as the console.
- A token issued before source tags were stored may still write when the caller names a tag that is an exact member of
EMET_SOURCE_TAGS. Refreshing that token is refused (invalid_grant): the client signs in again, and the new consent binds a registered tag. Those logins age out on their own. An empty registry has no members, so that fallback does not accept an arbitrary tag. - The local stdio client is the owner and can create guest and member codes. Over HTTP those codes still require an owner person. A member code can carry a registered source tag, set by the owner when the code is created and bound when the code is redeemed.
- A later verified
emet_session_openclearsdrops_unverifiedwhen the drop load succeeds, including when open drops remain. Only a failed drop load sets the flag. An open drop still has to be retired before the board is edited.
Fixed
- Session start lists the half-finished, dated, open, undecided, and parked rows it can read (
named_items). A section that is not a table is marked unread, including prose such as "None". Unread is not an empty list: the session still reads the document. An empty list is not a reason to skip the document. Nothing is hidden, and nothing is dropped because it is old. - The handoff refusal names
patch_docfor the board. Restoring the board counts as the board step. - Recall orders matches by how many of your words appear, then by importance. Current entries come first in every order, including time order. Pass
order: 'latest'for time order. A standalone "latest", "newest", or "most recent", together with other words, reorders those matches and does not change which rows match. "latest-budget", "not the latest", and a bare "latest" are ordinary keywords. - An entry that has expired or been superseded stays in recall and in layer queries. It is marked with the date it ended and, when a newer entry replaced it, which one. The current entry is listed first, including when you ask for the latest or sort by time. Pass
history: truewhen you need the ended entries and the current ones already fill the limit. - Revising an entry records the end date and the new entry's id on the old one. The old entry stays readable.
- Retired documents stay in the document list and in the startup scan, after the current ones, marked with the date they were retired and what replaced them. A retired drop is listed apart from the drops that still need a decision.
- A recall or a layer query ranks matching rows in the store before it keeps a bounded window (at least 200 rows, or 20 times the page). The rank is the same as the page: current entries first, then how many words match and importance, or time when you asked for the latest. A better match is not dropped for a lower importance or an older time. A blank sort value comes first when the order is ascending and last when it is descending. A word is matched as itself, so
$gtis that text. Capital and lower case count as the same match, includingÉcoleandécole.İmatches only itself. Full-width letters fold only with their full-width counterparts.ẞandßfold together. The page keeps the store's hit count, so the two do not disagree. The sort may use disk so a layer of large entries can finish.
Changed
- The public wording now matches the code on who can join (one owner; Guest is read-only and Member is read and write; both stay off until turned on), on the drop-cap buckets, and on working documents (
retire_docrefuses them; a rename marks the old id retired and the text stays). The charter states the monorail is enforce only, and that a templated write is checked, marked, and kept as the current revision.
Internal
- Tests now pin the guards a mutation check left unasserted, and the MCP SDK and proxy-addr dependencies are updated.
- Session close prunes size baselines only for sessions closed or idle more than 7 days, and only those keys. A live session's baseline on a document is not touched.
- An HTTP caller with no OAuth client id is stored as http:visitor, never in a stdio bucket.
- The test suite sets the boot-list store timeout short so a missing store does not stall the run.
- The HTTP visitor check calls the HTTP tool path with no OAuth client id, and the baseline prune check leaves a document with only live or fresh baselines unwritten.
Also included
- A module file is opened from
fileURLToPathandpath.resolve. On Windows,new URL(...).pathnameis/C:/..., and resolving that against aC:working directory producedC:\C:\...and the open failed. .env.exampleno longer assignsTRUST_PROXY. The server trusts exactly one proxy hop (Railway's edge) and does not read that variable.