mirror of
https://github.com/mudler/LocalAI.git
synced 2026-10-28 17:18:49 -04:00
* feat(addons): add the add-on runtime, navigation and first-party add-ons Add the add-on runtime to LocalAI: manifests, the host operation broker, admin gating by account role, the add-on UI bundle builder and the SDK for add-on pages. Move the navigation to Chat, Models, Add-ons and Settings, with pinned add-ons in the sidebar and an Add-ons drawer. Ship the first-party add-ons (voice, face, fine-tuning, quantization) as packages for linux/amd64, linux/arm64 and darwin/arm64. Intel macOS (darwin/amd64) is enabled in the platform files. Squashed from the review branch. The tree is unchanged; the pre-squash history is kept on a local backup branch. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(gosec): tighten file modes and annotate false positives Write job state, configs and imported models with mode 0600, clean the paths that are read from disk, and mark the route tables, the header name and the retry jitter as reviewed false positives. Assisted-by: Claude Code:claude-sonnet-5-5 gosec Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(addons): keep API keys off recovery mutations and same-site cookies POST /api/addons/dispatch forwarded the recovery and update mutations to the owner for any administrator key, which skipped the browser-session rule of their own routes. Refuse those actions there. Also apply the same-origin rule to the legacy token cookie, not only the session cookie, because the global CSRF check lets same-site requests through. Do not fail the start of LocalAI when an add-on library cannot be refreshed; log it and keep the installed add-ons up. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(addons): refuse a reinstall that would migrate retained data unbacked An upgrade takes a verified backup before the new package migrates the data. A reinstall over retained data has no running generation to stop, so the new package would migrate it without one. Refuse a reinstall whose data format differs from the retained one. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(addons): release the manager lock while a release is fetched Submit held the state lock across the catalog lookup and the package download, so the apps list and status reads stalled for the whole install. Serialize Submit and Reconcile with their own lock and drop the state lock around the fetch only. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(addons): kill an add-on only after three missed health probes One slow 100 ms probe killed a busy add-on and dropped the work it was serving. Require three misses in a row. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(ui): move settings under the operate hub The Operate hub already has Settings as a tab, so the sidebar no longer shows a separate Settings entry. The /app/settings route stays, and the hub tab still reaches it. The navigation test now expects Chat, Models and Add-ons as the primary items. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(addons): accept same-host browser requests that carry no fetch metadata Browsers do not send Sec-Fetch-* headers over plain HTTP on an address that is not localhost, so every add-on request from a LAN address was refused as cross-site. Keep refusing a Sec-Fetch-Site value other than same-origin. When the header is absent, accept the request only if its Origin, or failing that its Referer, names the same host and port as the request. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(ui): show the server's reason when an add-on request is refused A 403 or 400 answer showed a generic message and hid the reason in the response body, so a refusal by the browser guard could not be told from a missing permission. Show error.message from the body as the server sent it, and keep the generic text when the body has none. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(addons): run the add-on owner in the normal binary The owner was only enabled when an embedding host set the add-on config, so a normal run answered every add-on request as unavailable. Add --addons-enabled (default true) and --addons-ownership-mode (default named-user, or local-owner; anything else stops startup). The node is its own owner: state lives under the data path, and the carrier uses loopback keys made at each start and kept in memory. --addons-enabled=false turns the owner off completely. Named-user mode needs the account database. With authentication off the owner stays off and a warning says how to use local-owner. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(addons): keep the loopback owner address stable across restarts The single-node loopback transport took a new ephemeral port at each start. The owner stores its address in its identity file and refuses to start when the address differs, so every start after the first failed with "invalid addon owner configuration". Choose the port once, keep it in the add-on state root (loopback-port, mode 0600) and reuse it. If the port is taken at a later start, stop with an error that names the port and --addons-enabled=false, because another port would break the identity check. The keys and certificate stay in memory. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(addons): let add-on pages keep the host modules they were written against A page written for the web UI imports React, the router, i18next and a few shared components. The add-on builder refuses a bundle that holds a host file, so moving such a page into an add-on meant rewriting it. Add a compat mode to the shared builder. It answers those imports from a directory of stand-ins that read the SDK, bundles the dynamic import of the page code into the one output file, and collects the style sheets the page imports. A relative import that is not in the add-on's own source resolves to the file at the same path under the compat directory. Widen the SDK for these pages, without a version change: more host components (spinner, modal, lightbox, model picker) and hooks (models, resources, voice profiles, operations, MCP client), a style on icons, the icon names the pages draw, sdk.navigation.openApp to open a page of the app (only addresses under /app, and the way back as the only state) and sdk.portal. The shell passes the query string to the page. The stand-ins cover the router (the tab in the path, the model in the query), the translator over the host locale files, the core API calls through sdk.core.fetch, and byte copies of the pure helpers, with tests that keep the copies equal to the originals. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(addons): ship Studio and Talk as add-ons instead of built-in pages Studio and Talk were compiled into the web bundle and always listed in the Add-ons drawer. They are add-ons now, like Voice, Face, fine-tuning and quantization: a person installs and removes them, the drawer lists them only while they are installed, and they are packaged the same way. Move the pages, their components, hooks and helpers into addons/studio and addons/talk. Each has a manifest, a UI bundle, a release platform matrix and a catalog template, and is built by the compat mode of the shared builder. The core API stays where it is: the pages call it with the signed-in person's session. The history keeps its browser storage keys. The unit tests of the moved helpers move with them. In the core, drop the two pages, the Create group of the sidebar (Chat joins Home and Models in the old layout), the built-in catalog entries (the catalog is empty) and the talk locale namespace. The old addresses (/app/studio, /app/talk and the generator links) redirect to the add-on pages, with the model as ?model=. The Home /studio command is offered only while the Studio add-on is installed and opens it. The release workflow and its tests now list seven add-ons. Assisted-by: Claude Code:claude-sonnet-5-5 go node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): run the Studio and Talk specs against the add-on bundles The pages are add-ons now, so a spec that draws one installs the real built bundle first: the apps list names it and its module and style sheet are served from the build output, the way the add-on owner serves them. studio-addon.js holds that helper, and the Studio and Talk fixtures call it. Update the specs for the new addresses (/app/addons/studio/studio, the model as ?model=), the session permission the add-on route needs, the legacy redirects, the Home /studio command that appears only while the add-on is installed, and the sidebar without a Create group. Add specs for the add-ons themselves: every tab draws with no script error, the shell titles the page once, the old addresses say so when the add-on is not installed, a button of the page reaches a core page with the way back, and the drawer lists both only after they are installed. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(ui): centre the icon of a built-in tile in its icon box The drawer drew the icon of a built-in tile (Studio's palette was one) in a bare 40px box. Only the placeholder box was laid out as a centred grid with the 20px size, so the real icon sat in the top-left corner at the size of the page text. Give the built-in tile the same classes as the placeholder box, and check in a browser that the icon is centred. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * docs(addons): describe Studio and Talk as add-ons Replace the built-in list (now empty) with the Studio and Talk add-on sections, the new targets of the old links, the Home command, and the seven packaged add-ons. Describe the SDK additions the pages use: components, hooks, icons, openApp and portal. Say on the Studio page that it is installed from the drawer. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): click the shell title in the Studio slash-key spec The add-on shell titles the page, and the Studio overview no longer draws a second title, but the generator tabs keep theirs, so a bare h1 locator matched two elements. Click the first, which is the shell's. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(addons): read the loopback port file through os.Root The persisted port file was read with a path built from the add-on root, which gosec reports as a file inclusion through a variable. Open it through os.Root so the name cannot leave the root, even by a symbolic link, and require a regular file with no group or other access. A looser file now fails closed instead of being trusted. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): expect Settings under the Operate hub, not the sidebar Settings moved out of the sidebar into the Operate hub. The navigation spec still expected a sidebar link. Assert that the sidebar has no Settings entry, and that the Operate hub opens Settings as a tab. Assisted-by: Claude Code:claude-sonnet-5-5 playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): drop Settings from the 404 places Settings is a tab of the Operate hub and not a destination of its own, so the 404 page does not list it. Assert that it is absent. Assisted-by: Claude Code:claude-sonnet-5-5 playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): drive the media history and TTS specs through the Studio add-on The image, video, sound and speech generators are pages of the Studio add-on now, and the old addresses redirect to it. Install the add-on with the Studio fixtures, open its pages and use its compose card, so the specs run against the page that exists. Assisted-by: Claude Code:claude-sonnet-5-5 playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): count the first-run steps, not every list item The recommended models are a list inside the second step, so counting all list items read 3 only while the models were still loading. Count the step elements, which does not depend on the load order. Assisted-by: Claude Code:claude-sonnet-5-5 playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): fail the node refresh by state, not by call count The spec served the list to the first request and failed the rest. The first request is not always the one from the page, so the page could get the failure first and show no list. Serve the list until the page shows it, then fail the refreshes. Assisted-by: Claude Code:claude-sonnet-5-5 playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(addons): default to local-owner when auth is off A server without authentication has no accounts, so named-user left the add-on owner off. Resolve the unset mode in one place: local-owner when authentication is off, named-user when it is on. A flag or environment value still wins, and an unknown value is still refused. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(addons): register an official add-on library by default Add gallery/addons/index.yaml, a YAML index of the four first-party add-ons (fine-tuning, quantization, voice, face) in the library format. The entries come from addonpkg catalog over locally built linux/amd64 packages, so the digests pin those images. On the first start, when the owner has no sources.json, register the raw GitHub URL of that index on master as the "official" library and write the file. The file is then the record: a library the admin removes stays removed, and an existing file is never changed. --addons-official-library=false skips the default. Assisted-by: Claude Code:claude-sonnet-5-5 go node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * docs(addons): document the ownership default and the official library Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(addons): list Studio and Talk in the first-party index Add the Studio and Talk entries to gallery/addons/index.yaml next to the four existing ones. They come from addonpkg catalog over locally built linux/amd64 packages, so the digests pin those images. Assisted-by: Claude Code:claude-sonnet-5-5 go node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(addons): expect Studio and Talk in the official index The official index now lists six add-ons. Update the test that decodes it so it accepts Studio and Talk. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(addons): add a real icon to each first-party add-on Each icon is a 256 by 256 PNG: a rounded square in one colour of the UI kit palette with a white outline glyph from the kit sprite. Fine-tuning uses sliders, quantization layers, voice waveform, face user, studio palette, talk phone and tables database. They were rendered with headless Chrome from the sprite paths. Assisted-by: Claude Code:claude-sonnet-5-5 chrome Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(addons): ship a committed icon.png instead of the generated square The shared UI builder and the Tables builder copy ui/icon.png from the add-on source tree to the package unchanged when the file exists. They write the generated placeholder only when it does not. Add a fixture with an icon and a test for both cases. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(addons): list the tables add-on in the first-party index Add the Tables entry to gallery/addons/index.yaml next to the six existing ones. It comes from addonpkg catalog over a locally built linux/amd64 package, so the digest pins that image. The official index test now expects seven add-ons. Assisted-by: Claude Code:claude-sonnet-5-5 go node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(addons): make the Voice add-on one page with tabs The Voice add-on had four pages: recognition, library, create and speech, and the drawer listed two of them. It now has one page, "voice", and one drawer entry. Recognition, Library, Text to speech and From a recording are tabs of that page, drawn with the same tab strip the recognition page already used. The tab is the first path segment (voice/library), as in the Studio add-on, and the form that adds a voice is a view of the Library tab (voice/library/new). The old page names stay declared in the manifest. Each one redirects to its tab and keeps the query string, so saved links still open. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(ui): send the old voice routes to the Voice tabs /app/voice, /app/voice-library and /app/voice-library/new now open the matching tab of the Voice add-on page while the add-on is installed and running, and the core pages otherwise. The moved-page helper compares the first segment of the target with the declared pages, so a target can name a tab. The docs and the navigation spec list the new addresses. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(addons): cover the Voice tabs and the old page redirects The add-on unit tests render the tabs instead of the four pages. The Playwright spec checks the tab strip, the address of each tab, the missing Library tab for a member, and that the old page addresses of the add-on redirect to their tab with the query string kept. The migration table test follows the new targets. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(studio): keep the model menu inside a narrow screen The Home model picker sizes its menu from the viewport, and assumes the picker sits at the page gutter. In the Studio composer card the field is further in, so on a 390px screen the menu of the Sound expansion picker ended 7px past the right edge. Size the menu from the field it opens under instead. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): build the add-on bundles once for the whole run Each worker built the Studio and Talk bundles into the same dist directory, and the build empties that directory first. A worker that started, or restarted after a failure, removed the files another worker was serving, so a Studio spec saw "the style sheet of the add-on could not be loaded". Build once in a global setup before the workers start. A run without the setup still builds per worker. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): register the worker when the add-node spec says so The mocked roster added the worker on the third read of /api/nodes. The shell and the page both read it, and which one asks first depends on load, so the page could take the new worker as part of the roster it opened with and never show it as found. The worker now joins after the page shows it is listening. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): hold the gallery answer until the skeleton is seen The spec delayed the answer by a fixed 800 ms and then looked for the skeleton. The assertion polls at growing intervals, so on a slow machine it could step over that window. The answer now waits until the skeleton has been seen, and the spec then checks that the skeleton goes away. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): give the PDF tag the time the other PDF specs have pdf.js and its worker load on first use. The other specs in this file wait up to ten seconds for the result of that load. The first one waited five, and missed the tag on a busy machine. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): build the Face and Fine-tuning bundles in the global setup The navigation spec serves the built Fine-tuning bundle, but nothing built it, so two specs failed on a fresh checkout when the dist folder was missing. The spec also built the Face bundle in a hook that every worker runs, and a build rewrites the folder the other workers serve. The global setup now builds Studio, Talk, Face and Fine-tuning once, before the workers start. The spec builds the two bundles itself only when it runs without the global setup. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): fix the Home answers in the stale pin spec The spec asserts that the page shows no alert. The Home page raises its own alert when the model list fails or a staging operation has failed, and both answers come from the shared test server. A slow reply or a failed install left there counted as an alert about the pin. The spec now fixes both answers, so the alert count tells only about the pin. The assertions are unchanged. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): read the server address in the add-node spec from the page The spec expected the register address to carry port 8089, so it failed on any other port. It now expects the origin the page was opened from. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(addons): give the navigation routes spec its own catalog No page is built in today, so the catalog is empty and the three specs that expect the studio and talk entries failed on the list and on the pin seed. They passed only while Studio and Talk were built in. The spec now sets a catalog of two ungated entries for each example and restores the old one afterwards. The assertions are unchanged. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(cli): report a failed write of the MLX hostfile The tunnel callback ignored the error of os.WriteFile and set the hostfile variable even when the file was not written. It now logs the error and leaves the variable alone. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(addons): discard the close error of the held listener errcheck flags the deferred Close of the listener that keeps the port busy. The test has no use for that error, so the defer drops it explicitly. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(addons): move the add-on tool tests to Ginkgo The fine-tuning, quantization and add-on host library tests used t.Errorf, t.Fatal and t.Run, which the forbidigo rule rejects. They now use Describe, It and Gomega, with a suite bootstrap in each package. The cases and the assertions are the same. The tables in the host client and the tool schema tests keep one entry per case. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(addons): move the host operation tests to Ginkgo The hostops tests used the testing package calls that forbidigo rejects. They now run as Ginkgo specs under one suite bootstrap. Every check and every per-operation case is kept. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(addons): move the pin store tests to Ginkgo The pin service, file store, sweep and shared store contract tests used the testing package calls that forbidigo rejects. The store contract is now a function that registers its specs for each store, so the file store, the memory-only store and the database store run the same cases. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(addons): move the remaining add-on tests to Ginkgo The built-in catalog, tool arguments, loopback carrier, host operation contract, packaging, application, config, CLI and endpoint tests used the testing package calls that forbidigo rejects. They now run as Ginkgo specs. The endpoint tests also drop the unchecked Close errors that errcheck reports when the auth tag is on. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): wait for the targeted Reinstall button before the install click The "generic deletion blocks targeted install at confirmation" spec dispatches a popstate to set the target node, then clicks Reinstall with a script click. The click can run before the targeted page has rendered or while the button is still disabled, so no install request is sent and the poll on the install count times out. It failed 1 run in 10 with two workers and on every retry in CI. The spec now waits for the button to be enabled first. The assertions are unchanged. Assisted-by: Claude Code:claude-sonnet-5-5 playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * chore(addons): refresh the voice package digest in the first-party index The Voice add-on became one page with tabs and got a new icon, so the digest in gallery/addons/index.yaml no longer matched the build. Render the entry again with addonpkg catalog over a locally built linux/amd64 package; the main page is now voice. The other entries are unchanged. Assisted-by: Claude Code:claude-sonnet-5-5 go node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): wait for the target node's Reinstall button after the popstate The "generic deletion blocks targeted install at confirmation" spec dispatches a popstate to set the target node, then waits for a button named Reinstall and clicks it. Until React renders the targeted page, the page still draws the generic Reinstall button. It is enabled and has the same name, so the wait passed on it, the click started a global install, and no node install request was sent. The poll on the install count timed out with the confirm dialog still open. With the CPU throttled to 8x, the spec failed on 20 of 20 runs, and the button it clicked had the title "Reinstall". The spec now waits for the button titled "Reinstall on <node>". With the throttle it passes 30 of 30 runs. The assertions are unchanged. Assisted-by: Claude Code:claude-sonnet-5-5 playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): give the Studio hand-off spec a budget for the cold bundle load The "a result made through a hand-off records which result it came from" spec opens the Studio add-on straight from an address, twice. Each is a cold load: the page shows "Loading" until the add-on module has run, and the next assertion had the default five seconds. The load takes about two seconds on an idle run and seven to ten under CPU load, so the spec failed on a loaded machine with the hand-off note not yet drawn. With the CPU throttled to 6x and eight busy loops running, it failed on 21 of 30 runs. The first assertion after each load now waits up to 20 seconds, and the spec then passed 30 of 30 under the same load. The assertions are unchanged. Assisted-by: Claude Code:claude-sonnet-5-5 playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(addons): carry the identity page styles in the Face add-on The Face page is drawn with the shared identity views, but its style sheet held only the clip and error rules. The page, card, model list, known-faces table, enrol sheet and distance scale classes had no rules. They looked right only when the host had already loaded the style sheet of its own Faces page, which a visit through the add-on drawer does not do. Opened that way, the cards had no gap, the model list showed bullets, and the install buttons ran into the names. The Face sheet now holds the same identity rules as the core sheet, so the page looks the same whichever way it is opened. Assisted-by: Claude Code:claude-sonnet-5-5 playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(addons): scope the narrow-screen identity rules of the Voice add-on The rules for narrow screens (single-column pairs, smaller tool padding, compact rank rows) were copied into the Voice style sheet without their media query, so they applied at every width. They now sit in a max-width 720px query, and the reduced-motion rule in its own query, as in the core sheet. Assisted-by: Claude Code:claude-sonnet-5-5 playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(addons): drop the repeated title from the Voice and Face pages The add-on shell already titles the page, so the recognition pages showed the name twice: "Voice" above "Voices", "Face" above "Faces". Keep the supporting line and the model picker, as the Studio page does, and remove the unused title strings. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(ui): replace the Pinned sidebar section with an Apps entry The sidebar no longer lists pinned add-ons. It shows one Apps entry that opens the add-ons drawer, with a Show all link below it that opens the same drawer. Pins are used from the drawer, where a pinned tile keeps its pin and move buttons. The server pins API is unchanged. Remove the PinnedNav component and its locale title, rename the items.addons label to Apps, and update the e2e specs and the add-ons documentation to match. Assisted-by: Claude Code:claude-sonnet-5-5 playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(addons): assert the single shell title on the Voice and Face pages The add-on shell now shows the one title, "Voice" or "Face", and the page no longer repeats it. The tests still looked for the h1 "Voices" and "Faces". Assert that the add-on page has exactly one h1 and that it is the shell title. The core pages keep their own "Voices" and "Faces" titles. Assisted-by: Claude Code:claude-sonnet-5-5 playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(addons): drop the repeated title from the Voice Library and Text to speech pages The add-on shell already titles the page "Voice", so these two tabs showed a second heading below it ("Speech voices", "Speak text"). Keep the supporting line, as the Studio and recognition pages do, and remove the unused title strings. The e2e spec now checks that each tab has exactly one h1, the shell title. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(ui): list pinned apps under Apps in the sidebar A pinned app now shows as an indented child of the Apps entry, with its icon and title, in pin order. Show all stays the last child. The pins come from GET /api/addons/pins through the navigation context, and the apps from the add-on registry, which the drawer feeds on every list read, so the links follow the drawer. A pin without an installed app is not drawn, nothing extra shows when no app is pinned, and the children are hidden when the sidebar is collapsed to the rail. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * docs(addons): say that pinned apps are listed under Apps in the sidebar The sidebar lists the pinned apps between Apps and Show all, in pin order. The pins section and the navigation section said that pins do not appear in the sidebar. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(ui): remove the Show all link under Apps in the sidebar The link repeated the Apps entry, which opens the same drawer, and looked redundant when no app was pinned. Apps is now the only add-on entry; pinned apps still list under it in pin order. The link, its locale key and the style comment are gone, and the e2e spec and the add-ons docs now say that Apps is the only entry. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(ui): show a first-run card on Apps when nothing is installed An administrator who opens Apps with no add-on installed now sees a short card with three steps: choose a library, browse and install, start the add-on. Its button opens the Browse tab. The card is hidden once an add-on is installed and for anyone who cannot install. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(ui): hide the pinned apps in the icon rail When the window is narrower than 1024 px the sidebar shrinks to the icon rail by CSS alone, without the collapsed class. The pinned app links were still drawn there, with the indent meant for the full sidebar, so their icons sat to the right of the rail and were cut off. Hide the pinned app links in both rail states. The Apps entry keeps its centred icon. The e2e spec checks that the rail shows no pinned app and that every icon is centred at 1280 px collapsed and at 1000 px. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): stop the backend redirect test racing the installed list The test reads the redirected URL right after the path changes. The Backends page then loads the installed list and drops a selected backend that is not installed, so the backend parameter was sometimes already gone when the test read it. The mock server has no llama-cpp, and about 15 of 40 repeated runs failed on the backend assertion. The redirect itself was correct, including show_all. Serve the selected backend in the installed list, so the page keeps the selection and the assertions stay as strict as before. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(addons): accept a same-host Referer or Origin for human confirmation Browsers send no Sec-Fetch-* headers over plain HTTP on an address that is not localhost, so creating a resource from a LAN address failed with "Creating a resource requires your own browser session". When Sec-Fetch-Site is present it must still be same-origin with an empty destination, as before. When it is absent, Origin or, failing that, Referer must name the request host and port. A destination or mode that is present must still be the expected one. This matches the rule in BrowserProtection. The credential, token cookie, API key and tool-context checks are unchanged. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(ui): keep hub entries off the Apps route in the sidebar The Build hub still owned /app/addons through its legacy Add-ons tab, so the sidebar lit both Apps and Build on the Apps page. A tab whose gate is closed now owns no route when the sidebar asks, so only the Apps entry is active there. The hubs keep their own routes, and the legacy navigation still gives /app/addons to the Build hub. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(ui): label the pin control on app tiles and in the detail view The pin was a small icon-only button and hard to find. Each app tile now shows a button reading Pin, or Pinned with a filled pin, and the detail view has the same control in its header. Both toggle the same stored pin. The Apps grid lists pinned apps first, in pin order, then the others. The sidebar list and the server pins API are unchanged. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(addons): check the Voice From a recording tab has one title The Library and Text to speech tabs already assert that the add-on shell title is the only h1. Do the same for the From a recording tab, so a heading added there later fails the navigation spec. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(ui): stop the add-on shell drawing a title over add-on pages The app decides what its page shows. The shell drew the add-on name as a header above every add-on page, so an add-on could not choose its own title. The shell now draws no header on a live, loading or frozen add-on page; each add-on titles its own pages. The unavailable and missing-page states keep the name, because no add-on page is drawn there. The runtime and shell specs now check that the shell adds no page title. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(addons): let each add-on draw its own page title The shell no longer titles add-on pages, so each add-on draws one h1 per page. Voice titles its tabs "Voices" (Recognition and From a recording), "Speech voices" (Library) and "Speak text" (Text to speech); "Add a speech voice" already had its own. Face draws "Faces", Studio "Studio" and Talk "Talk". Tables promotes the database list and database name from h2 to h1. Fine-tuning and Quantization already drew a title. The add-on unit tests and the navigation and Studio specs now assert exactly one h1 per page, with the page's own title. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(addons): add a kind to library entries and read unknown kinds tolerantly A library entry now has an optional kind: addon (the default when it is absent), backend or model. Every index written before kinds existed stays valid and its entries are add-ons. A reader keeps the entries of the kinds it knows and skips the others without reading their fields, so a newer kind never makes an older host refuse the whole index. The refresh result and the library state report how many entries were skipped and of which kinds, and the refresh logs a warning. A kind that is not a plain kind name still makes the index malformed. Search lists add-ons unless the caller asks for a kind, and Resolve returns add-ons only, so an add-on install cannot be pointed at a backend image. A library policy may name the signer with an anchored identityRegex instead of an exact identity, so builds from master and from tags both verify. An add-on install refuses a policy that carries one. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(backends): install a backend from a library entry A library can now list backends. An entry of kind backend names the image of the backend gallery by digest, and POST /backends/library/install installs it on the local node. The gallery stays the source of truth and its install path is the one used: the library resolves the entry, takes the signature policy from the library, pins the image by digest and calls the same install as the gallery. Installing a name that came from a gallery, another library or by hand is refused and changes nothing. The signature policy of a backend library names the signer with an anchored identityRegex, so images signed by the merge workflow on master and on tags both verify. A pattern that is not anchored is refused. An install is bounded by a size limit per kind: add-ons keep 512 MiB and a backend image defaults to 8 GiB, set with --addons-backend-max-bytes. The limit reads the manifest after the signature check and before any layer is fetched. The metadata of an installed backend records the library it came from. scripts/backends/cmd/backendcatalog renders entries from backend/index.yaml and pins them against the registry. The pilot is the CPU build of local-store, in gallery/backends/index.yaml. The library is registered on the first start only with --addons-backend-library, which is off by default. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(ui): show the kind of library entries and install backends from them The Browse tab lists the entries of every kind this host reads and marks each one as an add-on or a backend. A backend installs through the backend route and not through the add-on lifecycle: the confirmation says that the backend gallery is not changed and that a backend runs native code, and a refusal of the host, such as a name installed from another origin, is shown with its own reason. The details give the kind, the alias and the signer pattern. The library editor can name the signer with a pattern. Without this a save would drop the pattern of a backend library. The Libraries tab reports the entries a refresh skipped because their kind is not read. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * docs(addons): describe backends in the library Document the entry kinds, how a reader skips a kind it does not know, the backend entry format, the signer identity pattern, the install route, the size limit of each kind, the pilot library and the command that renders it. The backend page links to it. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(mcp): install a backend from a library entry The backend library route installs a backend from an add-on library entry, and the admin REST surface and the MCP catalog must stay in step. Add the install_library_backend tool with an in-process and an HTTP client, the route map entry, the safety-rule listing and a skill recipe. Listing library entries stays on the add-on routes, which the assistant does not expose, so no list tool is added. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(ui): carry the add-on library keys in every locale The add-on library and backend library strings existed only in English, so the other locales had no value for them. Add the missing keys of the addons namespace to de, es, id, it, ko, pt-BR and zh-CN. The values are the English text until a translation is contributed. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Revert "feat(mcp): install a backend from a library entry" This reverts commit7493cff727. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Revert "docs(addons): describe backends in the library" This reverts commit57816ed7e6. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Revert "feat(ui): show the kind of library entries and install backends from them" This reverts commit49b2b151b7. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Revert "feat(backends): install a backend from a library entry" This reverts commit1d8d3e3421. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Revert "feat(addons): add a kind to library entries and read unknown kinds tolerantly" This reverts commit484813f856. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(ui): drop the backend library keys from the locales Revert the part of39f77ae29that added strings for backend libraries: the kind labels, the backend install texts, the signer identity pattern and the skipped entries notice. The add-on library keys stay. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(ui): add an add-ons control to the chat header Add-on tools were on or off only through the /addons command, with a toast and no state a person could see. The chat header now has an Add-ons button in the style of the MCP dropdown. It lists each running add-on that ships tools with a switch, and a badge shows how many are on. The chat keeps the ids that are on (addonToolIds) next to the older boolean, and both are saved with the chat. A chat that has only the boolean means every add-on. The request sends addon_tools alone when every add-on is on, and adds addon_tool_ids when only some are. /addons turns all on or all off and uses the same state. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(addons): let a chat request name the add-ons whose tools it uses addon_tools=true still offers the tools of every add-on the caller may use. A new addon_tool_ids metadata key, a comma-separated list of add-on ids, narrows that to some add-ons. The list counts only with the opt-in, and a list that names nothing offers no tool rather than all of them. The executor drops the tools of add-ons that are not listed and refuses a call to one as an unknown tool, so a model cannot reach a tool the person turned off. Both keys are consumed so they do not reach the backend. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(addons): cover the per-add-on tool list and the chat header control Go tests cover the list form (the list filters the tools offered and the calls allowed) and the unchanged boolean form. Unit tests cover the chat add-on rules. Playwright specs cover the header control: listing only add-ons that ship tools, toggling each one, the count, /addons in step with the switches, and the request metadata. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): check each add-on page has one title when not enabled The shell names an add-on only where the add-on page cannot mount (not enabled, failed, no UI, bundle not loaded, no such page). Once the page mounts it draws its own title, including when it says it is not enabled on this server, and the shell draws none. The shell code already works this way; this change states the rule beside the unavailable state and pins it in the specs. The shell spec now expects exactly one title in the unavailable states. The navigation spec checks the Face page without a face model (the add-on title only) and the Face page of a stopped add-on (the shell title only). Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(addons): upgrade add-ons on their own when the setting is on A new auto_upgrade_addons setting (flag LOCALAI_AUTO_UPGRADE_ADDONS, default off) lets the owner upgrade an installed add-on when its library lists a newer version. It follows the backend setting: a startup flag, a runtime setting, and the same schedule as the backend update check (a first pass shortly after start, then every six hours). Each pass fetches the library of every installed add-on, and for each available update builds the same pinned upgrade command an administrator sends and runs it through the same lifecycle path. The channel rules, the signer identity, the digest checks, the SDK compatibility check and the backup before the upgrade all apply unchanged. The only difference is the gate: the owner acts on its own setting, so no administrator is asked. A refused or failed upgrade changes nothing and is logged; a candidate that failed is not retried until the library lists another digest. With the setting off, nothing runs and upgrades stay manual. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(ui): add the Upgrade add-ons automatically toggle to Settings The toggle sits beside Upgrade backends automatically and is off by default. It saves the auto_upgrade_addons runtime setting. The English locale gets the label key, and the Settings test fixture lists the new field. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(addons): cover the automatic upgrade setting and document it The setting defaults to off in the config, the runtime settings and the flag, and is read back from the saved settings file. With it on, a real owner upgrades an installed add-on through the manager; with it off, nothing changes, and a change of the setting at run time takes effect on the next pass. The manager specs show the upgrade goes through the same pinned path as the manual one, and that a corrupted package, a failed signature policy, an incompatible release, a missing update checker and a caller who is not an administrator each leave the installed version in place. The new specs are added to the lifecycle case inventory. The add-ons page describes the setting, its schedule and its default. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactor(addons): name the library entry identifier id The library entry of an add-on used addonId while the shared envelope and the model entries use id. Release now has the field ID, written as id, and every writer emits it: the index encoder, the package workflow templates, the catalog generator and gallery/addons/index.yaml. The digests in the index did not change. DecodeIndex still reads addonId as a legacy alias for one release, so an existing library and a library served by an older tool keep working. An entry that holds both names is refused. The Apps UI reads id and falls back to addonId. Assisted-by: Claude Code:claude-sonnet-5-5 go node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(addons): use the id field in the auto-upgrade test release The auto-upgrade test arrived after the identifier rename and still named the release field AddonID, so the application tests did not build. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(addons): annotate the auto-upgrade actor label for gosec The actor label looks like a credential to gosec G101. It is a fixed name for upgrades the owner starts itself. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(schema): persist the per-chat add-on tool fields The chat header persists addonTools and addonToolIds, but Conversation had no fields for them, so the server dropped them on save. Add both and update the generated swagger files by hand because swag is not installed here. Assisted-by: Claude Code:claude-sonnet-5-5 go Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): count the add-ons auto-upgrade setting in the settings groups The setting sits in the Backends and galleries group, once. The page now lists 54 settings plus the three branding images, so the spec expects 57. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): pause the fake clock ahead of now in the clear-all spec The fake clock runs from install, so pausing at the current time failed with 'Cannot fast-forward to the past' on a slow runner. The save itself is synchronous and was not lost. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(ui): hold the Studio capabilities reply longer in the skeleton spec 800 ms was shorter than a slow runner needs to render the page, so the skeleton was gone before the check. The product shows it. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(i18n): add the French add-ons locale Master added the fr locale after this branch forked. The add-ons unit test requires every locale to carry the add-ons namespace, so fr needs its own addons.json. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto <mudler@localai.io> --------- Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
3456 lines
252 KiB
JSON
3456 lines
252 KiB
JSON
{
|
|
"prerequisites": {
|
|
"kind": "shell",
|
|
"commands": [
|
|
[
|
|
"sh",
|
|
"scripts/addons/prerequisites_test.sh"
|
|
]
|
|
],
|
|
"cases": [
|
|
"missing-go",
|
|
"old-go",
|
|
"future-go",
|
|
"old-node",
|
|
"wrong-node",
|
|
"wrong-protoc",
|
|
"absent-generated",
|
|
"empty-name",
|
|
"future-suite",
|
|
"empty-selection",
|
|
"failed-child",
|
|
"failed-case-named",
|
|
"failed-tail-kept",
|
|
"zero-tests",
|
|
"skipped-tests",
|
|
"exact-tag-pin",
|
|
"wrong-tag-sum",
|
|
"ginkgo-empty",
|
|
"ginkgo-skipped",
|
|
"ginkgo-missing",
|
|
"ginkgo-failed-spec-named",
|
|
"ginkgo-failure-message",
|
|
"browser-setup-failure",
|
|
"configured-browser-missing",
|
|
"configured-browser-setup",
|
|
"contracts-empty",
|
|
"contracts-skipped",
|
|
"gateway-missing-report",
|
|
"gateway-skipped-report",
|
|
"ui-report-failed",
|
|
"ui-report-skipped",
|
|
"ui-report-flaky",
|
|
"ui-report-empty",
|
|
"ui-report-missing",
|
|
"leak-ignores-command-line",
|
|
"leak-finds-working-directory"
|
|
],
|
|
"readiness": {
|
|
"ginkgo": {
|
|
"command": [
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"<temporary SQLite probe>",
|
|
"-ginkgo.json-report=<unique report>"
|
|
],
|
|
"cases": [
|
|
"sqlite transaction"
|
|
]
|
|
},
|
|
"commands": [
|
|
[
|
|
"sh",
|
|
"scripts/addons/prepare.sh",
|
|
"--check"
|
|
],
|
|
[
|
|
"tests/e2e-ui/ui-test-server",
|
|
"--mock-backend=<absolute mock-backend>",
|
|
"--port=<isolated port>"
|
|
],
|
|
[
|
|
"core/http/react-ui/node_modules/.bin/playwright",
|
|
"--version"
|
|
],
|
|
[
|
|
"node",
|
|
"--input-type=module",
|
|
"-e",
|
|
"<browser readiness probe>",
|
|
"<healthy server URL>"
|
|
]
|
|
],
|
|
"cases": [
|
|
"toolchain",
|
|
"server health",
|
|
"browser"
|
|
]
|
|
}
|
|
},
|
|
"contracts": {
|
|
"kind": "ginkgo",
|
|
"commands": [
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./pkg/addons/contract",
|
|
"-ginkgo.json-report=../../../.cache/addons/logs/contracts.json"
|
|
]
|
|
],
|
|
"cases": [
|
|
"accepts independent service tool page and chat capabilities",
|
|
"rejects invalid namespace IDs and executable paths",
|
|
"rejects add-on IDs that the host serves as a route segment",
|
|
"rejects invalid versions ranges and capabilities",
|
|
"rejects unknown duplicate trailing and oversized manifest JSON",
|
|
"rejects incompatible host API protocol SDK data and platform fixtures",
|
|
"validates UI only when declared and rejects inconsistent contributions",
|
|
"uses canonical version one wire fixtures",
|
|
"rejects incomplete expired or forged authority shapes",
|
|
"rejects unknown and oversized wire payloads",
|
|
"validates finite defaults overrides and cross field bounds",
|
|
"validates preview receipt states and output descriptions",
|
|
"accepts the apps surface fields and keeps headless manifests valid",
|
|
"rejects unknown and reserved launch modes",
|
|
"rejects remote data absolute and traversing icon paths",
|
|
"requires the main page to be one of the declared pages",
|
|
"bounds localized titles and descriptions and rejects markup",
|
|
"requires the existence tool of an addon whose resources are created or deleted",
|
|
"reserves the segments of the navigation routes",
|
|
"refuses an add-on that needs a newer SDK than the host provides, and says so",
|
|
"accepts a range that contains the host SDK",
|
|
"accepts a range that spans the host SDK",
|
|
"refuses an add-on built for SDK 1 only on a version 2 host",
|
|
"keeps the generic message for a range that is malformed",
|
|
"accepts a read tool that names no resource",
|
|
"keeps a create tool free of the resource argument",
|
|
"refuses a read tool that offers the resource without requiring it",
|
|
"refuses a write or schema tool without a resource",
|
|
"still accepts a read tool that requires its resource",
|
|
"still accepts a write or schema tool that requires its resource"
|
|
],
|
|
"report": ".cache/addons/logs/contracts.json"
|
|
},
|
|
"catalog": {
|
|
"kind": "ginkgo",
|
|
"commands": [
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/services/addons/catalog",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/catalog.json"
|
|
]
|
|
],
|
|
"cases": [
|
|
"fetches private bearer and basic catalogs without OCI credentials",
|
|
"blocks redirects without leaking credentials or error details",
|
|
"keeps duplicate names source scoped and excludes disabled sources",
|
|
"reports refresh failures rather than serving stale success",
|
|
"resolves the host platform from a multi platform catalog",
|
|
"selects exact configured owner targets and rejects absent or ambiguous targets",
|
|
"requires authoritative administration for all source edits",
|
|
"persists protected references and removes sources without touching installs",
|
|
"invalidates cached releases on explicit source changes",
|
|
"rejects secret URLs invalid digests duplicate identities and malformed catalogs",
|
|
"refuses a library entry whose add-on ID is a host route segment",
|
|
"lists and gets protected source copies including disabled and empty sources after reload",
|
|
"requires current authoritative administration and context for source reads",
|
|
"serializes source reads with concurrent configuration edits",
|
|
"pins channels and restricts package transport to secure or opted in loopback origins",
|
|
"surfaces optional UI metadata in search results and resolutions without changing plain entries",
|
|
"rejects entries with remote icons, reserved launch modes, markup or overlong display text",
|
|
"lists only releases the configured target platform can install",
|
|
"keeps the compatibility hint of an entry and refuses a malformed range",
|
|
"lists the releases of one add-on for every platform, from the cache, and refuses a failed library",
|
|
"names an unavailable credential reference as a credential failure inside the refresh failure",
|
|
"reads a YAML list of releases with the documented fields",
|
|
"accepts an empty library written as an empty list",
|
|
"refuses a JSON index",
|
|
"refuses an unknown field, at the top and inside ui",
|
|
"refuses a second document, a mapping, an empty body and a duplicate key",
|
|
"refuses duplicate identities",
|
|
"enforces the release count and the size limit"
|
|
],
|
|
"report": ".cache/addons/logs/catalog.json"
|
|
},
|
|
"packages": {
|
|
"kind": "ginkgo",
|
|
"commands": [
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/services/addons/packages",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/packages.json"
|
|
]
|
|
],
|
|
"cases": [
|
|
"stages verified HTTP bytes and commits immutable receipts without activation",
|
|
"rejects untrusted integrity forged releases and digest mismatches",
|
|
"rejects traversal links collisions and excessive extraction",
|
|
"rejects cancellation disk full and preserves existing packages",
|
|
"rejects platform data API SDK and missing asset mismatches",
|
|
"pins and verifies real local OCI distribution bytes without a container runtime",
|
|
"rejects downloaded digest mismatch redirects cancellation and file count limits",
|
|
"accepts optional UI only with real immutable assets and rejects non executable entrypoints",
|
|
"does not allow remote verification policy to replace owner trust",
|
|
"requires source opt in before any plaintext OCI request",
|
|
"bounds compressed OCI PAX expansion before tar parsing",
|
|
"bounds compressed OCI GNU expansion before tar parsing",
|
|
"counts padding trailing bytes and layers at the exact expanded boundary",
|
|
"denies nonloopback plaintext and redirect responses at the transport boundary",
|
|
"bounds expanded bytes cumulatively across real OCI layers",
|
|
"bounds sparse logical output across files and layers preserving old packages",
|
|
"accepts exact sparse output budget and cancels synthesized writes",
|
|
"stages real trusted signatures and rejects signed identity digest and trust mismatches offline",
|
|
"records the digest of a packaged immutable icon in the receipt and refuses unusable icons"
|
|
],
|
|
"report": ".cache/addons/logs/packages.json"
|
|
},
|
|
"lifecycle": {
|
|
"kind": "ginkgo",
|
|
"commands": [
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/services/addons",
|
|
"-ginkgo.json-report=../../../.cache/addons/logs/lifecycle.json"
|
|
]
|
|
],
|
|
"cases": [
|
|
"recovers every durable journal boundary without replaying publication",
|
|
"removes abandoned staging without removing published packages on recovery",
|
|
"keeps immutable history on successful upgrade and reinstallation",
|
|
"excludes competing owners and rejects conflicting durable identities",
|
|
"never opens replica roots or elects an absent owner",
|
|
"binds duplicate operation IDs to actor and command and serializes conflicts",
|
|
"refuses commands and asset reads for an add-on ID the host serves as a route",
|
|
"retains generations identity data and grants across uninstall and restart",
|
|
"preserves old packages and active generation on manager upgrade failure",
|
|
"requires current authoritative administration even for idempotent retries",
|
|
"rejects symlinked package roots without touching external staging",
|
|
"executes enabled owner intent on startup and stops on disable and close without forwarder execution",
|
|
"retries runtime synchronization after canceled disable and generation upgrade",
|
|
"binds lifecycle lookup to current admin and original actor without writes or repair",
|
|
"cancels status lookup while a lifecycle writer holds the journal lock",
|
|
"denies enable and disable for a stale generation without recording anything",
|
|
"lists the identifiers of installed addons, disabled ones included",
|
|
"refuses to list installed identifiers while recovery is required",
|
|
"lists apps by visibility and serves an icon only for a visible app at its generation",
|
|
"reports the supervisor state of an app through a crash and a restart",
|
|
"reads a flat directory in batches and stops at the entry bound",
|
|
"adds up nested files and reports a complete walk as not truncated",
|
|
"never follows or counts a symbolic link",
|
|
"keeps a result for a short time so polling does not walk again",
|
|
"stops at the time bound and reports a truncated size",
|
|
"does not keep a result cut short by the caller",
|
|
"is what the installed view reports for the data directory",
|
|
"resolves a package for the current enabled generation and digest only",
|
|
"answers from the current installed manifest only and follows a generation change",
|
|
"reports a digest-only change of a moving channel, applies nothing and offers the pinned upgrade",
|
|
"refuses a second operation ID for the same transition, in flight or done, and applies it once",
|
|
"runs concurrent requests with one operation ID once and gives each the same answer",
|
|
"serializes conflicting upgrades by the installed digest and refuses the loser without a record",
|
|
"refuses a candidate that is not the one the library resolves now",
|
|
"refuses an upgrade to the digest that is already installed",
|
|
"rechecks compatibility at execution and refuses an incompatible candidate",
|
|
"selects a newer immutable version and treats a rewritten version as an integrity error",
|
|
"keeps the last good generation when the candidate cannot be staged",
|
|
"never switches the library or channel, and a failed check is never up to date",
|
|
"lets an administrator refresh and everyone with the feature read a redacted status",
|
|
"shows the pending update in the apps list from the cache only",
|
|
"does not accept pins without an update checker or on another action",
|
|
"keeps the unpinned typed upgrade of an earlier release working",
|
|
"carries the SDK refusal text to the caller of a failed install and keeps the generic error",
|
|
"installs an add-on whose SDK range contains the host SDK",
|
|
"upgrades an installed add-on through the same path as a manual upgrade",
|
|
"does nothing when no newer version is listed",
|
|
"refuses a candidate whose package no longer matches its listed digest and replaces nothing",
|
|
"refuses a candidate that fails the signature policy of its library and replaces nothing",
|
|
"does not upgrade to a release the host cannot run",
|
|
"does nothing without an update checker",
|
|
"keeps the manual upgrade closed to a caller who is not an administrator"
|
|
],
|
|
"report": ".cache/addons/logs/lifecycle.json"
|
|
},
|
|
"runtime": {
|
|
"kind": "ginkgo",
|
|
"commands": [
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/services/addons/runtime",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/runtime.json"
|
|
]
|
|
],
|
|
"cases": [
|
|
"registers only ready generation bound service headless and UI capabilities",
|
|
"rejects forged registration nonloopback and stale incarnation handshakes",
|
|
"bounds readiness and handles exit during start and stop",
|
|
"withdraws immediately drains boundedly and rejects stale process identities",
|
|
"exhausts restart budget without retaining dead registrations",
|
|
"does not inherit secrets and exits when the private parent channel closes",
|
|
"rejects foreign supervisor handles and numeric PID substitutions",
|
|
"resets restart budget only after sustained authenticated health",
|
|
"authenticates every request and separates trusted authority from model arguments",
|
|
"bounds output streams cancellation deadlines and stop admission",
|
|
"tells a 409 conflict of the add-on from an outage",
|
|
"rejects nonloopback endpoints and bounds oversized streams and concurrency",
|
|
"never reports failed between a launch starting and the restarted process being published",
|
|
"reserves a draining slot against concurrent starts",
|
|
"waits for a restart launch worker before acknowledging stop",
|
|
"exposes a new incarnation client after restart without reviving the old client",
|
|
"kills the exact paused child of a killed owner before launching its replacement",
|
|
"fails closed on ambiguous launch identities and preserves unrelated reused PIDs",
|
|
"retains a canceled restart slot until cleanup completes and rejects duplicate supervisors",
|
|
"refuses a missing established ledger and fences failed cleanup publication",
|
|
"withdraws and initiates every live slot before a cleanup timeout",
|
|
"reports stopped, running, failed, starting and running again across a crash and a restart",
|
|
"keeps reporting failed once the restart budget is exhausted",
|
|
"creates one private data directory per addon and passes its path in the startup object",
|
|
"gives no data directory without a data root and refuses an unsafe root or addon ID",
|
|
"gives an add-on that the host setting names a host endpoint of its own",
|
|
"gives an add-on that the host setting does not name no host endpoint",
|
|
"closes the host endpoint when the incarnation ends",
|
|
"an HTTP 400 answer",
|
|
"an HTTP 422 answer",
|
|
"keeps a bounded, printable reason and nothing else of the body",
|
|
"leaves 503, 500 and 404 as outages",
|
|
"types a withdrawn client, a full slot table, a bad envelope and a missing schema as not sent",
|
|
"keeps a not-sent error an ErrRuntime for callers that do not tell them apart",
|
|
"types a refused connection as not sent",
|
|
"never types a possibly-sent request as not sent"
|
|
],
|
|
"report": ".cache/addons/logs/runtime.json"
|
|
},
|
|
"gateway": {
|
|
"kind": "ginkgo",
|
|
"commands": [
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/services/addons/gateway",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/gateway.json"
|
|
],
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/http/endpoints/addons",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/gateway-http.json"
|
|
]
|
|
],
|
|
"cases": [
|
|
"serves only declared installed generation assets and rejects traversal",
|
|
"fails closed without current identity or resource policy and reports the original ID of an unknown mutation outcome",
|
|
"reports an unclassified account check error as unavailable on every path and a wrapped denial as forbidden",
|
|
"propagates interrupted progress cancellation through the receiving frontend",
|
|
"validates finite relay budgets and prevents disabling polling bounds",
|
|
"builds a carrier only from complete pinned identities",
|
|
"types an unknown mutation outcome as unavailable without losing its operation",
|
|
"rejects untrusted peers wrong audience body expiry replay and revoked credentials",
|
|
"alternates pinned frontends and rejects untrusted certificates without local fallback",
|
|
"reports the original operation after lost mutation replies without retrying",
|
|
"rejects a stream longer than its receiving frontend budget",
|
|
"rejects a CA signed peer without a pin on the owner side",
|
|
"refuses an owner whose CA signed certificate is not the pinned owner",
|
|
"returns the artifact status through the owner from every frontend with one denial for the rest",
|
|
"types the owner's refusal and outage of a lookup the same from every frontend",
|
|
"writes an attachment header that cannot be broken out of",
|
|
"rotates the enforced audience on restart and rejects captured requests",
|
|
"never expires the response deadline after the relay returned",
|
|
"returns the owner's forbidden status for an invalid kind and for missing policy",
|
|
"still reports unavailable when the owner is unable to serve and not forbidden",
|
|
"reaches the same decision through both frontends and delivers bytes when allowed",
|
|
"keeps aborting when revocation happens after bytes were written",
|
|
"bounds progress, asset and file relays by their own limit",
|
|
"alternates real owner journal status and terminates coarse progress without submitting again",
|
|
"reports an account store outage as unavailable and a refused account as forbidden",
|
|
"rejects unknown lifecycle argument fields before touching the owner journal",
|
|
"reports a runtime that cannot serve as unavailable through both frontends",
|
|
"reports an output that ends before its first byte as unavailable",
|
|
"fails closed as unavailable for an unclassified owner error",
|
|
"keeps authorization and policy denials forbidden",
|
|
"keeps a mutation unknown when the runtime fails after the owner applied it",
|
|
"keeps a mutation unknown when the owner reports recovery required for its operation",
|
|
"reports a mutation as unknown when the owner cannot serve it at all",
|
|
"keeps a mutation unknown on the owner's own frontend and leaves reads and denials alone",
|
|
"lets unavailability win when an error wraps both a denial and an unavailable cause",
|
|
"does not leak attachment headers into an error when the first read fails",
|
|
"treats every action except the known reads as a mutation",
|
|
"keeps resolved resources under admission for JSON and attachment bytes",
|
|
"closes interrupted output and releases admission on disconnect",
|
|
"rechecks revoked credentials during attachment copying",
|
|
"adopts read outputs as private artifacts inside admission and replaces a forged resource identity",
|
|
"refuses at ingest a file result larger than the relay file bound so nothing unservable is staged",
|
|
"denies private relays without host resolution and admission",
|
|
"serves declared assets of the current enabled generation by package digest only",
|
|
"allows only an exact declared tool name and fails closed otherwise",
|
|
"never contacts the add-on for an undeclared tool and still serves a declared one",
|
|
"denies a repeated key at any depth however it is spelled",
|
|
"denies arguments that are not exactly one object",
|
|
"separates a denial from an unavailable declaration source",
|
|
"answers 503 and never contacts the add-on when the source is unavailable or the arguments repeat a key",
|
|
"is the typed invalid request on the owner for a read, never an outage",
|
|
"is the typed invalid request on the owner for a proposal call",
|
|
"is the typed invalid request on the owner for a json relay",
|
|
"is the same typed answer from a forwarding frontend",
|
|
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
|
|
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
|
|
"denies sharing and deletion proposals and an unauthenticated caller",
|
|
"serves the local owner's confirmation only from a same-origin fetch of the host page",
|
|
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
|
|
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
|
|
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
|
|
"tells an editor of a blocked write only that it is denied",
|
|
"returns the applied proposal when the confirmed operation committed",
|
|
"answers an owner outage by the owner's state with the same type from every frontend",
|
|
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
|
|
"documents the proposal routes and the proposal schema in the Swagger spec",
|
|
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
|
|
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
|
|
"checks browser CSRF feature and admin access with real stored keys",
|
|
"serves a private file result as a safe attachment over real HTTP",
|
|
"never renders hostile names or active media types inline",
|
|
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
|
|
"denies the download of a disabled addon and serves it again after enable",
|
|
"relays the same bytes, headers and denials through two forwarding frontends",
|
|
"keeps a file result of a read denied whole without an artifact store",
|
|
"serves the local owner's file only in local-owner mode",
|
|
"documents the artifact routes and the artifact schema in the Swagger spec",
|
|
"rejects anonymous callers and forged forwarding headers",
|
|
"gates the feature and then administration for named keys",
|
|
"requires same-origin browser requests for cookie mutations",
|
|
"registers only the dispatch, relay and proposal mutations",
|
|
"reserves every first path segment the host registers under /api/addons",
|
|
"gates the artifact routes by authentication and feature",
|
|
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
|
|
"rejects anonymous and forged forwarding authority through real authentication",
|
|
"lets callers through only when the deployment selected local-owner mode",
|
|
"keeps authentication, the feature gate and administration when accounts exist",
|
|
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
|
|
"documents every field the error responses emit in the Swagger schema",
|
|
"reports an unavailable read as plain unavailability",
|
|
"reports a denial as forbidden",
|
|
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
|
|
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
|
|
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
|
|
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
|
|
"serves the verified icon through the host route and denies it identically otherwise",
|
|
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
|
|
"documents the apps routes and every field of the app view in the Swagger spec",
|
|
"lists every registered addon route in the feature registry",
|
|
"gates the apps routes by authentication, feature and administration",
|
|
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
|
|
"refuses every management call of the owner itself for a caller that is not an administrator",
|
|
"saves, refreshes and removes a library by reference and leaves installed addons alone",
|
|
"upgrades an installed addon through the typed action and keeps its earlier generation",
|
|
"reports a lost source change as an unknown outcome and a lost read as unavailable",
|
|
"documents the management actions and every emitted field of the installed view",
|
|
"serves the declared files of the current package through every frontend with immutable headers",
|
|
"lists the same URLs the route serves, and only for an enabled addon",
|
|
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
|
|
"accepts a same-origin browser session and refuses a cross-site or direct one",
|
|
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
|
|
"refuses a declared file that is not a regular file of the package",
|
|
"documents the asset route and its binary response in the Swagger spec",
|
|
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
|
|
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
|
|
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
|
|
"checks only for an administrator's own browser session, and applies nothing",
|
|
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
|
|
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
|
|
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
|
|
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
|
|
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
|
|
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend"
|
|
],
|
|
"report": ".cache/addons/logs/gateway.json",
|
|
"reports": [
|
|
{
|
|
"path": ".cache/addons/logs/gateway.json",
|
|
"cases": [
|
|
"serves only declared installed generation assets and rejects traversal",
|
|
"fails closed without current identity or resource policy and reports the original ID of an unknown mutation outcome",
|
|
"reports an unclassified account check error as unavailable on every path and a wrapped denial as forbidden",
|
|
"propagates interrupted progress cancellation through the receiving frontend",
|
|
"validates finite relay budgets and prevents disabling polling bounds",
|
|
"builds a carrier only from complete pinned identities",
|
|
"types an unknown mutation outcome as unavailable without losing its operation",
|
|
"rejects untrusted peers wrong audience body expiry replay and revoked credentials",
|
|
"alternates pinned frontends and rejects untrusted certificates without local fallback",
|
|
"reports the original operation after lost mutation replies without retrying",
|
|
"rejects a stream longer than its receiving frontend budget",
|
|
"rejects a CA signed peer without a pin on the owner side",
|
|
"refuses an owner whose CA signed certificate is not the pinned owner",
|
|
"returns the artifact status through the owner from every frontend with one denial for the rest",
|
|
"types the owner's refusal and outage of a lookup the same from every frontend",
|
|
"writes an attachment header that cannot be broken out of",
|
|
"rotates the enforced audience on restart and rejects captured requests",
|
|
"never expires the response deadline after the relay returned",
|
|
"returns the owner's forbidden status for an invalid kind and for missing policy",
|
|
"still reports unavailable when the owner is unable to serve and not forbidden",
|
|
"reaches the same decision through both frontends and delivers bytes when allowed",
|
|
"keeps aborting when revocation happens after bytes were written",
|
|
"bounds progress, asset and file relays by their own limit",
|
|
"alternates real owner journal status and terminates coarse progress without submitting again",
|
|
"reports an account store outage as unavailable and a refused account as forbidden",
|
|
"rejects unknown lifecycle argument fields before touching the owner journal",
|
|
"reports a runtime that cannot serve as unavailable through both frontends",
|
|
"reports an output that ends before its first byte as unavailable",
|
|
"fails closed as unavailable for an unclassified owner error",
|
|
"keeps authorization and policy denials forbidden",
|
|
"keeps a mutation unknown when the runtime fails after the owner applied it",
|
|
"keeps a mutation unknown when the owner reports recovery required for its operation",
|
|
"reports a mutation as unknown when the owner cannot serve it at all",
|
|
"keeps a mutation unknown on the owner's own frontend and leaves reads and denials alone",
|
|
"lets unavailability win when an error wraps both a denial and an unavailable cause",
|
|
"does not leak attachment headers into an error when the first read fails",
|
|
"treats every action except the known reads as a mutation",
|
|
"keeps resolved resources under admission for JSON and attachment bytes",
|
|
"closes interrupted output and releases admission on disconnect",
|
|
"rechecks revoked credentials during attachment copying",
|
|
"adopts read outputs as private artifacts inside admission and replaces a forged resource identity",
|
|
"refuses at ingest a file result larger than the relay file bound so nothing unservable is staged",
|
|
"denies private relays without host resolution and admission",
|
|
"serves declared assets of the current enabled generation by package digest only",
|
|
"allows only an exact declared tool name and fails closed otherwise",
|
|
"never contacts the add-on for an undeclared tool and still serves a declared one",
|
|
"denies a repeated key at any depth however it is spelled",
|
|
"denies arguments that are not exactly one object",
|
|
"separates a denial from an unavailable declaration source",
|
|
"answers 503 and never contacts the add-on when the source is unavailable or the arguments repeat a key",
|
|
"is the typed invalid request on the owner for a read, never an outage",
|
|
"is the typed invalid request on the owner for a proposal call",
|
|
"is the typed invalid request on the owner for a json relay",
|
|
"is the same typed answer from a forwarding frontend"
|
|
]
|
|
},
|
|
{
|
|
"path": ".cache/addons/logs/gateway-http.json",
|
|
"cases": [
|
|
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
|
|
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
|
|
"denies sharing and deletion proposals and an unauthenticated caller",
|
|
"serves the local owner's confirmation only from a same-origin fetch of the host page",
|
|
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
|
|
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
|
|
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
|
|
"tells an editor of a blocked write only that it is denied",
|
|
"returns the applied proposal when the confirmed operation committed",
|
|
"answers an owner outage by the owner's state with the same type from every frontend",
|
|
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
|
|
"documents the proposal routes and the proposal schema in the Swagger spec",
|
|
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
|
|
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
|
|
"checks browser CSRF feature and admin access with real stored keys",
|
|
"serves a private file result as a safe attachment over real HTTP",
|
|
"never renders hostile names or active media types inline",
|
|
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
|
|
"denies the download of a disabled addon and serves it again after enable",
|
|
"relays the same bytes, headers and denials through two forwarding frontends",
|
|
"keeps a file result of a read denied whole without an artifact store",
|
|
"serves the local owner's file only in local-owner mode",
|
|
"documents the artifact routes and the artifact schema in the Swagger spec",
|
|
"rejects anonymous callers and forged forwarding headers",
|
|
"gates the feature and then administration for named keys",
|
|
"requires same-origin browser requests for cookie mutations",
|
|
"registers only the dispatch, relay and proposal mutations",
|
|
"reserves every first path segment the host registers under /api/addons",
|
|
"gates the artifact routes by authentication and feature",
|
|
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
|
|
"rejects anonymous and forged forwarding authority through real authentication",
|
|
"lets callers through only when the deployment selected local-owner mode",
|
|
"keeps authentication, the feature gate and administration when accounts exist",
|
|
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
|
|
"documents every field the error responses emit in the Swagger schema",
|
|
"reports an unavailable read as plain unavailability",
|
|
"reports a denial as forbidden",
|
|
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
|
|
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
|
|
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
|
|
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
|
|
"serves the verified icon through the host route and denies it identically otherwise",
|
|
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
|
|
"documents the apps routes and every field of the app view in the Swagger spec",
|
|
"lists every registered addon route in the feature registry",
|
|
"gates the apps routes by authentication, feature and administration",
|
|
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
|
|
"refuses every management call of the owner itself for a caller that is not an administrator",
|
|
"saves, refreshes and removes a library by reference and leaves installed addons alone",
|
|
"upgrades an installed addon through the typed action and keeps its earlier generation",
|
|
"reports a lost source change as an unknown outcome and a lost read as unavailable",
|
|
"documents the management actions and every emitted field of the installed view",
|
|
"serves the declared files of the current package through every frontend with immutable headers",
|
|
"lists the same URLs the route serves, and only for an enabled addon",
|
|
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
|
|
"accepts a same-origin browser session and refuses a cross-site or direct one",
|
|
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
|
|
"refuses a declared file that is not a regular file of the package",
|
|
"documents the asset route and its binary response in the Swagger spec",
|
|
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
|
|
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
|
|
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
|
|
"checks only for an administrator's own browser session, and applies nothing",
|
|
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
|
|
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
|
|
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
|
|
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
|
|
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
|
|
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend",
|
|
"returns the SDK refusal text to the administrator and the generic message for an unrelated failure",
|
|
"returns the same text through a forwarding frontend"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"policy": {
|
|
"kind": "ginkgo",
|
|
"commands": [
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/services/addons/policy",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/policy.json"
|
|
]
|
|
],
|
|
"cases": [
|
|
"enforces the viewer editor owner matrix on fixture resources",
|
|
"denies installation administrators and unrelated users any access to user data",
|
|
"does not leak resource existence and treats unknown actions as owner mutations",
|
|
"never grants the owner role or a grant to the owner and the synthetic principals",
|
|
"rejects anonymous and legacy synthetic principals in named mode",
|
|
"checks credential and account status on every admission",
|
|
"keeps no current-user state shared between concurrent admissions",
|
|
"disables sharing in explicit local-owner mode and lets every local caller own the resource",
|
|
"refuses a mode switch of populated data without a stopped backed-up migration",
|
|
"retains resources and grants across a restart and an uninstall of the package",
|
|
"refuses a corrupt store and a second opener",
|
|
"stops admitted work of a revoked user and acknowledges only after it ended",
|
|
"lets a racing revocation win against read and write admissions",
|
|
"serializes writes per resource while reads run concurrently",
|
|
"bounds the revocation wait and does not acknowledge a stuck drain",
|
|
"invalidates pending proposals on revoke and downgrade and fails closed when it cannot",
|
|
"requires explicit creation authority and keeps pending registrations inaccessible",
|
|
"reconciles a registration interrupted by a crash from the durable store",
|
|
"keeps a record whose existence cannot be established and settles the rest",
|
|
"never drops a committed resource and counts pending quota unchanged",
|
|
"retries kept records from the loop on a tick and on a kick, and stops on Close",
|
|
"closes a loop that never started without waiting",
|
|
"maps opaque ids to the trusted addon and owner and keeps an absent policy denying",
|
|
"does not acknowledge a retried downgrade while the lowered user's write still runs",
|
|
"retries a failed proposal invalidation after the lowered grant is already durable",
|
|
"keeps the drain owed across a restart",
|
|
"does not cancel work admitted under a later grant when a lowering is retried",
|
|
"still waits for and cancels work admitted before the lowering when the regrant is retried",
|
|
"stops work admitted after a regrant when the role is lowered again",
|
|
"keeps the epoch of the owed drain across a restart",
|
|
"keeps a drain mark that a concurrent lowering replaced while a retry was waiting",
|
|
"maps a store outage to unavailable and a disabled account to forbidden",
|
|
"caps pending and committed registrations per user and in total",
|
|
"applies finite defaults when no limit is configured",
|
|
"denies creation as unavailable when the authority cannot tell",
|
|
"reports an unclassified account or creation check error as unavailable and a definite denial as forbidden",
|
|
"does not start the work when revocation cancels the admission before run",
|
|
"rejects persisted unknown roles and trailing bytes without resetting the store",
|
|
"removes stale temporary files on open",
|
|
"stops accepting writes after a failed directory sync and keeps the applied change",
|
|
"retains resources and grants across a real manager uninstall and restart",
|
|
"stores a pending proposal with its exact effects and never executes it",
|
|
"applies exactly the stored arguments once and answers a repeat from the stored receipt",
|
|
"refuses changed arguments, other actors, unknown identifiers and an unbound digest",
|
|
"never lets an API key, plain text or a boolean approve",
|
|
"accepts the local owner as the confirming principal in local-owner mode only",
|
|
"expires a proposal and refuses a late or repeated confirmation",
|
|
"refuses a proposal made stale by a new generation or a moved revision",
|
|
"cancels a proposal for good and restricts who may propose which action",
|
|
"never accepts sharing, deletion, reads or unclassified actions as proposals",
|
|
"cancels pending proposals when authority is lowered and lets a revocation win the confirmation race",
|
|
"persists every transition atomically before it is reported",
|
|
"does not dispatch when the executing state cannot be made durable",
|
|
"keeps a lost reply unknown, blocks conflicting writes and resolves it by receipt without a replay",
|
|
"reports a lost reply from the owner's own gateway with the original operation",
|
|
"recovers a crash after dispatch by receipt and a crash before dispatch as unknown without replay",
|
|
"keeps pending proposals across a restart and never resets a corrupt store",
|
|
"bounds the pending proposals of one user and the store as a whole",
|
|
"records expiry and collects settled proposals without any read so a quiet clock cannot fill the store",
|
|
"records expiry durably when the owner starts and when it recovers",
|
|
"keeps settled proposals for the retention window only",
|
|
"keeps one user from starving others and never drops another user's live proposal",
|
|
"bounds the stored canonical arguments per user and in total with a typed quota error",
|
|
"looks an unresolved receipt up again with backoff for a finite window and never applies again",
|
|
"lets only the resource owner's browser session abandon an unresolved outcome and then unblocks writes",
|
|
"records a late receipt of an abandoned outcome instead of hiding it",
|
|
"settles by lookup instead of abandoning when the receipt is final",
|
|
"refuses a stored abandonment that names nobody and keeps looking up in the background",
|
|
"binds the digest to the operation, actor, resource, generation, action, arguments and revision",
|
|
"refuses a stored proposal whose operation, actor, resource, generation or arguments changed at rest",
|
|
"issues resource identifiers the envelope contract accepts",
|
|
"is unavailable until it is attached to a policy and a runtime",
|
|
"keeps executing, outcome-unknown and abandoned records far past retention and still dedupes them",
|
|
"waits for the background run and for lookups in flight before it closes, and writes nothing after",
|
|
"lets the owner role list the unresolved proposals of its resource and abandon one by the listed digest",
|
|
"names the blocking proposal in the denial only to the resource owner",
|
|
"refuses an unbound digest when the owner abandons through the gateway or the broker",
|
|
"answers the same typed outage for a resolution whoever proposed the operation",
|
|
"returns the applied proposal when the owner cannot read it back after a successful apply",
|
|
"does not show another user's blocking operation in a proposal view",
|
|
"denies a proposal for an undeclared tool before any preview and stores nothing",
|
|
"denies a proposal that names a tool when no tool source is installed",
|
|
"rechecks the stored tool at confirmation and never applies a withdrawn tool",
|
|
"denies a proposal whose arguments repeat a key and stores nothing",
|
|
"reports an unavailable declaration source as unavailable, never as a denial",
|
|
"does not apply at confirmation while the declaration source is unavailable, and applies once it recovers",
|
|
"reserves a create proposal as a pending resource that nobody can reach",
|
|
"commits the reservation on confirmation and makes the proposer the private owner",
|
|
"abandons the reservation when a create proposal is cancelled or expires",
|
|
"abandons the reservation when the addon rejects the creation",
|
|
"keeps a lost create reply pending and unknown and settles it by receipt",
|
|
"abandons an unknown create only when the addon confirms the backing is absent",
|
|
"settles reservations at restart by asking the addon and keeps those of live proposals",
|
|
"bounds concurrent create proposals by the pending quota",
|
|
"lets only the proposer confirm, cancel or read a create proposal",
|
|
"denies a create proposal when creation authority is revoked before confirmation",
|
|
"denies a create proposal for an undeclared tool or an existing resource without reserving",
|
|
"does not let reconcile drop the reservation of a creation in flight",
|
|
"commits the reservation at recovery when the crash came after the receipt was stored",
|
|
"never reads an add-on that cannot answer as a backing that is gone",
|
|
"accepts the explicit answer of the declared existence tool, true or false",
|
|
"holds the resources of one add-on and leaves another add-on alone",
|
|
"cancels admitted work and reports a drain that did not finish",
|
|
"restores grants through the account directory and the lowerings since the backup, never beyond them",
|
|
"keeps a bounded durable log of lowered access",
|
|
"keeps a revocation however many later lowerings of another person follow",
|
|
"restores the data but no access when the history may have lost a lowering",
|
|
"reads a store that is full of lowerings as one whose history may be cut",
|
|
"applies a lowering made after the export whatever time the backup is given",
|
|
"refuses a change that was authorized just before the hold began",
|
|
"cancels a pending proposal and leaves an executing one outcome-unknown after a restore",
|
|
"forgets the records of one add-on and no other",
|
|
"maps an owner on a restore to a local-owner store only when nothing named is in it",
|
|
"migrates the ownership of a stopped store with a backup and an explicit mapping and refuses a populated downgrade",
|
|
"refuses a proposal whose preview the add-on refused, storing nothing",
|
|
"settles a confirmation the add-on refused as rejected, never as an unknown outcome"
|
|
],
|
|
"report": ".cache/addons/logs/policy.json"
|
|
},
|
|
"proposals": {
|
|
"kind": "ginkgo",
|
|
"commands": [
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/services/addons/policy",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/proposals.json"
|
|
],
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/http/endpoints/addons",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/proposals-http.json"
|
|
]
|
|
],
|
|
"cases": [
|
|
"requires explicit creation authority and keeps pending registrations inaccessible",
|
|
"reconciles a registration interrupted by a crash from the durable store",
|
|
"keeps a record whose existence cannot be established and settles the rest",
|
|
"never drops a committed resource and counts pending quota unchanged",
|
|
"retries kept records from the loop on a tick and on a kick, and stops on Close",
|
|
"closes a loop that never started without waiting",
|
|
"stops admitted work of a revoked user and acknowledges only after it ended",
|
|
"lets a racing revocation win against read and write admissions",
|
|
"serializes writes per resource while reads run concurrently",
|
|
"bounds the revocation wait and does not acknowledge a stuck drain",
|
|
"invalidates pending proposals on revoke and downgrade and fails closed when it cannot",
|
|
"maps a store outage to unavailable and a disabled account to forbidden",
|
|
"maps opaque ids to the trusted addon and owner and keeps an absent policy denying",
|
|
"disables sharing in explicit local-owner mode and lets every local caller own the resource",
|
|
"refuses a mode switch of populated data without a stopped backed-up migration",
|
|
"retains resources and grants across a restart and an uninstall of the package",
|
|
"refuses a corrupt store and a second opener",
|
|
"caps pending and committed registrations per user and in total",
|
|
"applies finite defaults when no limit is configured",
|
|
"denies creation as unavailable when the authority cannot tell",
|
|
"does not acknowledge a retried downgrade while the lowered user's write still runs",
|
|
"retries a failed proposal invalidation after the lowered grant is already durable",
|
|
"keeps the drain owed across a restart",
|
|
"does not start the work when revocation cancels the admission before run",
|
|
"retains resources and grants across a real manager uninstall and restart",
|
|
"rejects persisted unknown roles and trailing bytes without resetting the store",
|
|
"removes stale temporary files on open",
|
|
"stops accepting writes after a failed directory sync and keeps the applied change",
|
|
"enforces the viewer editor owner matrix on fixture resources",
|
|
"denies installation administrators and unrelated users any access to user data",
|
|
"does not leak resource existence and treats unknown actions as owner mutations",
|
|
"never grants the owner role or a grant to the owner and the synthetic principals",
|
|
"does not cancel work admitted under a later grant when a lowering is retried",
|
|
"still waits for and cancels work admitted before the lowering when the regrant is retried",
|
|
"stops work admitted after a regrant when the role is lowered again",
|
|
"keeps the epoch of the owed drain across a restart",
|
|
"keeps a drain mark that a concurrent lowering replaced while a retry was waiting",
|
|
"reports an unclassified account or creation check error as unavailable and a definite denial as forbidden",
|
|
"rejects anonymous and legacy synthetic principals in named mode",
|
|
"checks credential and account status on every admission",
|
|
"keeps no current-user state shared between concurrent admissions",
|
|
"stores a pending proposal with its exact effects and never executes it",
|
|
"applies exactly the stored arguments once and answers a repeat from the stored receipt",
|
|
"refuses changed arguments, other actors, unknown identifiers and an unbound digest",
|
|
"never lets an API key, plain text or a boolean approve",
|
|
"accepts the local owner as the confirming principal in local-owner mode only",
|
|
"expires a proposal and refuses a late or repeated confirmation",
|
|
"refuses a proposal made stale by a new generation or a moved revision",
|
|
"cancels a proposal for good and restricts who may propose which action",
|
|
"never accepts sharing, deletion, reads or unclassified actions as proposals",
|
|
"cancels pending proposals when authority is lowered and lets a revocation win the confirmation race",
|
|
"persists every transition atomically before it is reported",
|
|
"does not dispatch when the executing state cannot be made durable",
|
|
"keeps a lost reply unknown, blocks conflicting writes and resolves it by receipt without a replay",
|
|
"reports a lost reply from the owner's own gateway with the original operation",
|
|
"recovers a crash after dispatch by receipt and a crash before dispatch as unknown without replay",
|
|
"keeps pending proposals across a restart and never resets a corrupt store",
|
|
"bounds the pending proposals of one user and the store as a whole",
|
|
"records expiry and collects settled proposals without any read so a quiet clock cannot fill the store",
|
|
"records expiry durably when the owner starts and when it recovers",
|
|
"keeps settled proposals for the retention window only",
|
|
"keeps one user from starving others and never drops another user's live proposal",
|
|
"bounds the stored canonical arguments per user and in total with a typed quota error",
|
|
"looks an unresolved receipt up again with backoff for a finite window and never applies again",
|
|
"lets only the resource owner's browser session abandon an unresolved outcome and then unblocks writes",
|
|
"records a late receipt of an abandoned outcome instead of hiding it",
|
|
"settles by lookup instead of abandoning when the receipt is final",
|
|
"refuses a stored abandonment that names nobody and keeps looking up in the background",
|
|
"binds the digest to the operation, actor, resource, generation, action, arguments and revision",
|
|
"refuses a stored proposal whose operation, actor, resource, generation or arguments changed at rest",
|
|
"issues resource identifiers the envelope contract accepts",
|
|
"is unavailable until it is attached to a policy and a runtime",
|
|
"keeps executing, outcome-unknown and abandoned records far past retention and still dedupes them",
|
|
"waits for the background run and for lookups in flight before it closes, and writes nothing after",
|
|
"lets the owner role list the unresolved proposals of its resource and abandon one by the listed digest",
|
|
"names the blocking proposal in the denial only to the resource owner",
|
|
"refuses an unbound digest when the owner abandons through the gateway or the broker",
|
|
"answers the same typed outage for a resolution whoever proposed the operation",
|
|
"returns the applied proposal when the owner cannot read it back after a successful apply",
|
|
"does not show another user's blocking operation in a proposal view",
|
|
"denies a proposal for an undeclared tool before any preview and stores nothing",
|
|
"denies a proposal that names a tool when no tool source is installed",
|
|
"rechecks the stored tool at confirmation and never applies a withdrawn tool",
|
|
"denies a proposal whose arguments repeat a key and stores nothing",
|
|
"reports an unavailable declaration source as unavailable, never as a denial",
|
|
"does not apply at confirmation while the declaration source is unavailable, and applies once it recovers",
|
|
"reserves a create proposal as a pending resource that nobody can reach",
|
|
"commits the reservation on confirmation and makes the proposer the private owner",
|
|
"abandons the reservation when a create proposal is cancelled or expires",
|
|
"abandons the reservation when the addon rejects the creation",
|
|
"keeps a lost create reply pending and unknown and settles it by receipt",
|
|
"abandons an unknown create only when the addon confirms the backing is absent",
|
|
"settles reservations at restart by asking the addon and keeps those of live proposals",
|
|
"bounds concurrent create proposals by the pending quota",
|
|
"lets only the proposer confirm, cancel or read a create proposal",
|
|
"denies a create proposal when creation authority is revoked before confirmation",
|
|
"denies a create proposal for an undeclared tool or an existing resource without reserving",
|
|
"does not let reconcile drop the reservation of a creation in flight",
|
|
"commits the reservation at recovery when the crash came after the receipt was stored",
|
|
"never reads an add-on that cannot answer as a backing that is gone",
|
|
"accepts the explicit answer of the declared existence tool, true or false",
|
|
"holds the resources of one add-on and leaves another add-on alone",
|
|
"cancels admitted work and reports a drain that did not finish",
|
|
"restores grants through the account directory and the lowerings since the backup, never beyond them",
|
|
"keeps a bounded durable log of lowered access",
|
|
"keeps a revocation however many later lowerings of another person follow",
|
|
"restores the data but no access when the history may have lost a lowering",
|
|
"reads a store that is full of lowerings as one whose history may be cut",
|
|
"applies a lowering made after the export whatever time the backup is given",
|
|
"refuses a change that was authorized just before the hold began",
|
|
"cancels a pending proposal and leaves an executing one outcome-unknown after a restore",
|
|
"forgets the records of one add-on and no other",
|
|
"maps an owner on a restore to a local-owner store only when nothing named is in it",
|
|
"migrates the ownership of a stopped store with a backup and an explicit mapping and refuses a populated downgrade",
|
|
"refuses a proposal whose preview the add-on refused, storing nothing",
|
|
"settles a confirmation the add-on refused as rejected, never as an unknown outcome",
|
|
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
|
|
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
|
|
"denies sharing and deletion proposals and an unauthenticated caller",
|
|
"serves the local owner's confirmation only from a same-origin fetch of the host page",
|
|
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
|
|
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
|
|
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
|
|
"tells an editor of a blocked write only that it is denied",
|
|
"returns the applied proposal when the confirmed operation committed",
|
|
"answers an owner outage by the owner's state with the same type from every frontend",
|
|
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
|
|
"documents the proposal routes and the proposal schema in the Swagger spec",
|
|
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
|
|
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
|
|
"checks browser CSRF feature and admin access with real stored keys",
|
|
"serves a private file result as a safe attachment over real HTTP",
|
|
"never renders hostile names or active media types inline",
|
|
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
|
|
"denies the download of a disabled addon and serves it again after enable",
|
|
"relays the same bytes, headers and denials through two forwarding frontends",
|
|
"keeps a file result of a read denied whole without an artifact store",
|
|
"serves the local owner's file only in local-owner mode",
|
|
"documents the artifact routes and the artifact schema in the Swagger spec",
|
|
"rejects anonymous callers and forged forwarding headers",
|
|
"gates the feature and then administration for named keys",
|
|
"requires same-origin browser requests for cookie mutations",
|
|
"registers only the dispatch, relay and proposal mutations",
|
|
"reserves every first path segment the host registers under /api/addons",
|
|
"gates the artifact routes by authentication and feature",
|
|
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
|
|
"rejects anonymous and forged forwarding authority through real authentication",
|
|
"lets callers through only when the deployment selected local-owner mode",
|
|
"keeps authentication, the feature gate and administration when accounts exist",
|
|
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
|
|
"documents every field the error responses emit in the Swagger schema",
|
|
"reports an unavailable read as plain unavailability",
|
|
"reports a denial as forbidden",
|
|
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
|
|
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
|
|
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
|
|
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
|
|
"serves the verified icon through the host route and denies it identically otherwise",
|
|
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
|
|
"documents the apps routes and every field of the app view in the Swagger spec",
|
|
"lists every registered addon route in the feature registry",
|
|
"gates the apps routes by authentication, feature and administration",
|
|
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
|
|
"refuses every management call of the owner itself for a caller that is not an administrator",
|
|
"saves, refreshes and removes a library by reference and leaves installed addons alone",
|
|
"upgrades an installed addon through the typed action and keeps its earlier generation",
|
|
"reports a lost source change as an unknown outcome and a lost read as unavailable",
|
|
"documents the management actions and every emitted field of the installed view",
|
|
"serves the declared files of the current package through every frontend with immutable headers",
|
|
"lists the same URLs the route serves, and only for an enabled addon",
|
|
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
|
|
"accepts a same-origin browser session and refuses a cross-site or direct one",
|
|
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
|
|
"refuses a declared file that is not a regular file of the package",
|
|
"documents the asset route and its binary response in the Swagger spec",
|
|
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
|
|
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
|
|
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
|
|
"checks only for an administrator's own browser session, and applies nothing",
|
|
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
|
|
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
|
|
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
|
|
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
|
|
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
|
|
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend"
|
|
],
|
|
"report": ".cache/addons/logs/proposals.json",
|
|
"reports": [
|
|
{
|
|
"path": ".cache/addons/logs/proposals.json",
|
|
"cases": [
|
|
"requires explicit creation authority and keeps pending registrations inaccessible",
|
|
"reconciles a registration interrupted by a crash from the durable store",
|
|
"keeps a record whose existence cannot be established and settles the rest",
|
|
"never drops a committed resource and counts pending quota unchanged",
|
|
"retries kept records from the loop on a tick and on a kick, and stops on Close",
|
|
"closes a loop that never started without waiting",
|
|
"stops admitted work of a revoked user and acknowledges only after it ended",
|
|
"lets a racing revocation win against read and write admissions",
|
|
"serializes writes per resource while reads run concurrently",
|
|
"bounds the revocation wait and does not acknowledge a stuck drain",
|
|
"invalidates pending proposals on revoke and downgrade and fails closed when it cannot",
|
|
"maps a store outage to unavailable and a disabled account to forbidden",
|
|
"maps opaque ids to the trusted addon and owner and keeps an absent policy denying",
|
|
"disables sharing in explicit local-owner mode and lets every local caller own the resource",
|
|
"refuses a mode switch of populated data without a stopped backed-up migration",
|
|
"retains resources and grants across a restart and an uninstall of the package",
|
|
"refuses a corrupt store and a second opener",
|
|
"caps pending and committed registrations per user and in total",
|
|
"applies finite defaults when no limit is configured",
|
|
"denies creation as unavailable when the authority cannot tell",
|
|
"does not acknowledge a retried downgrade while the lowered user's write still runs",
|
|
"retries a failed proposal invalidation after the lowered grant is already durable",
|
|
"keeps the drain owed across a restart",
|
|
"does not start the work when revocation cancels the admission before run",
|
|
"retains resources and grants across a real manager uninstall and restart",
|
|
"rejects persisted unknown roles and trailing bytes without resetting the store",
|
|
"removes stale temporary files on open",
|
|
"stops accepting writes after a failed directory sync and keeps the applied change",
|
|
"enforces the viewer editor owner matrix on fixture resources",
|
|
"denies installation administrators and unrelated users any access to user data",
|
|
"does not leak resource existence and treats unknown actions as owner mutations",
|
|
"never grants the owner role or a grant to the owner and the synthetic principals",
|
|
"does not cancel work admitted under a later grant when a lowering is retried",
|
|
"still waits for and cancels work admitted before the lowering when the regrant is retried",
|
|
"stops work admitted after a regrant when the role is lowered again",
|
|
"keeps the epoch of the owed drain across a restart",
|
|
"keeps a drain mark that a concurrent lowering replaced while a retry was waiting",
|
|
"reports an unclassified account or creation check error as unavailable and a definite denial as forbidden",
|
|
"rejects anonymous and legacy synthetic principals in named mode",
|
|
"checks credential and account status on every admission",
|
|
"keeps no current-user state shared between concurrent admissions",
|
|
"stores a pending proposal with its exact effects and never executes it",
|
|
"applies exactly the stored arguments once and answers a repeat from the stored receipt",
|
|
"refuses changed arguments, other actors, unknown identifiers and an unbound digest",
|
|
"never lets an API key, plain text or a boolean approve",
|
|
"accepts the local owner as the confirming principal in local-owner mode only",
|
|
"expires a proposal and refuses a late or repeated confirmation",
|
|
"refuses a proposal made stale by a new generation or a moved revision",
|
|
"cancels a proposal for good and restricts who may propose which action",
|
|
"never accepts sharing, deletion, reads or unclassified actions as proposals",
|
|
"cancels pending proposals when authority is lowered and lets a revocation win the confirmation race",
|
|
"persists every transition atomically before it is reported",
|
|
"does not dispatch when the executing state cannot be made durable",
|
|
"keeps a lost reply unknown, blocks conflicting writes and resolves it by receipt without a replay",
|
|
"reports a lost reply from the owner's own gateway with the original operation",
|
|
"recovers a crash after dispatch by receipt and a crash before dispatch as unknown without replay",
|
|
"keeps pending proposals across a restart and never resets a corrupt store",
|
|
"bounds the pending proposals of one user and the store as a whole",
|
|
"records expiry and collects settled proposals without any read so a quiet clock cannot fill the store",
|
|
"records expiry durably when the owner starts and when it recovers",
|
|
"keeps settled proposals for the retention window only",
|
|
"keeps one user from starving others and never drops another user's live proposal",
|
|
"bounds the stored canonical arguments per user and in total with a typed quota error",
|
|
"looks an unresolved receipt up again with backoff for a finite window and never applies again",
|
|
"lets only the resource owner's browser session abandon an unresolved outcome and then unblocks writes",
|
|
"records a late receipt of an abandoned outcome instead of hiding it",
|
|
"settles by lookup instead of abandoning when the receipt is final",
|
|
"refuses a stored abandonment that names nobody and keeps looking up in the background",
|
|
"binds the digest to the operation, actor, resource, generation, action, arguments and revision",
|
|
"refuses a stored proposal whose operation, actor, resource, generation or arguments changed at rest",
|
|
"issues resource identifiers the envelope contract accepts",
|
|
"is unavailable until it is attached to a policy and a runtime",
|
|
"keeps executing, outcome-unknown and abandoned records far past retention and still dedupes them",
|
|
"waits for the background run and for lookups in flight before it closes, and writes nothing after",
|
|
"lets the owner role list the unresolved proposals of its resource and abandon one by the listed digest",
|
|
"names the blocking proposal in the denial only to the resource owner",
|
|
"refuses an unbound digest when the owner abandons through the gateway or the broker",
|
|
"answers the same typed outage for a resolution whoever proposed the operation",
|
|
"returns the applied proposal when the owner cannot read it back after a successful apply",
|
|
"does not show another user's blocking operation in a proposal view",
|
|
"denies a proposal for an undeclared tool before any preview and stores nothing",
|
|
"denies a proposal that names a tool when no tool source is installed",
|
|
"rechecks the stored tool at confirmation and never applies a withdrawn tool",
|
|
"denies a proposal whose arguments repeat a key and stores nothing",
|
|
"reports an unavailable declaration source as unavailable, never as a denial",
|
|
"does not apply at confirmation while the declaration source is unavailable, and applies once it recovers",
|
|
"reserves a create proposal as a pending resource that nobody can reach",
|
|
"commits the reservation on confirmation and makes the proposer the private owner",
|
|
"abandons the reservation when a create proposal is cancelled or expires",
|
|
"abandons the reservation when the addon rejects the creation",
|
|
"keeps a lost create reply pending and unknown and settles it by receipt",
|
|
"abandons an unknown create only when the addon confirms the backing is absent",
|
|
"settles reservations at restart by asking the addon and keeps those of live proposals",
|
|
"bounds concurrent create proposals by the pending quota",
|
|
"lets only the proposer confirm, cancel or read a create proposal",
|
|
"denies a create proposal when creation authority is revoked before confirmation",
|
|
"denies a create proposal for an undeclared tool or an existing resource without reserving",
|
|
"does not let reconcile drop the reservation of a creation in flight",
|
|
"commits the reservation at recovery when the crash came after the receipt was stored",
|
|
"never reads an add-on that cannot answer as a backing that is gone",
|
|
"accepts the explicit answer of the declared existence tool, true or false",
|
|
"holds the resources of one add-on and leaves another add-on alone",
|
|
"cancels admitted work and reports a drain that did not finish",
|
|
"restores grants through the account directory and the lowerings since the backup, never beyond them",
|
|
"keeps a bounded durable log of lowered access",
|
|
"keeps a revocation however many later lowerings of another person follow",
|
|
"restores the data but no access when the history may have lost a lowering",
|
|
"reads a store that is full of lowerings as one whose history may be cut",
|
|
"applies a lowering made after the export whatever time the backup is given",
|
|
"refuses a change that was authorized just before the hold began",
|
|
"cancels a pending proposal and leaves an executing one outcome-unknown after a restore",
|
|
"forgets the records of one add-on and no other",
|
|
"maps an owner on a restore to a local-owner store only when nothing named is in it",
|
|
"migrates the ownership of a stopped store with a backup and an explicit mapping and refuses a populated downgrade",
|
|
"refuses a proposal whose preview the add-on refused, storing nothing",
|
|
"settles a confirmation the add-on refused as rejected, never as an unknown outcome"
|
|
]
|
|
},
|
|
{
|
|
"path": ".cache/addons/logs/proposals-http.json",
|
|
"cases": [
|
|
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
|
|
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
|
|
"denies sharing and deletion proposals and an unauthenticated caller",
|
|
"serves the local owner's confirmation only from a same-origin fetch of the host page",
|
|
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
|
|
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
|
|
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
|
|
"tells an editor of a blocked write only that it is denied",
|
|
"returns the applied proposal when the confirmed operation committed",
|
|
"answers an owner outage by the owner's state with the same type from every frontend",
|
|
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
|
|
"documents the proposal routes and the proposal schema in the Swagger spec",
|
|
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
|
|
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
|
|
"checks browser CSRF feature and admin access with real stored keys",
|
|
"serves a private file result as a safe attachment over real HTTP",
|
|
"never renders hostile names or active media types inline",
|
|
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
|
|
"denies the download of a disabled addon and serves it again after enable",
|
|
"relays the same bytes, headers and denials through two forwarding frontends",
|
|
"keeps a file result of a read denied whole without an artifact store",
|
|
"serves the local owner's file only in local-owner mode",
|
|
"documents the artifact routes and the artifact schema in the Swagger spec",
|
|
"rejects anonymous callers and forged forwarding headers",
|
|
"gates the feature and then administration for named keys",
|
|
"requires same-origin browser requests for cookie mutations",
|
|
"registers only the dispatch, relay and proposal mutations",
|
|
"reserves every first path segment the host registers under /api/addons",
|
|
"gates the artifact routes by authentication and feature",
|
|
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
|
|
"rejects anonymous and forged forwarding authority through real authentication",
|
|
"lets callers through only when the deployment selected local-owner mode",
|
|
"keeps authentication, the feature gate and administration when accounts exist",
|
|
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
|
|
"documents every field the error responses emit in the Swagger schema",
|
|
"reports an unavailable read as plain unavailability",
|
|
"reports a denial as forbidden",
|
|
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
|
|
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
|
|
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
|
|
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
|
|
"serves the verified icon through the host route and denies it identically otherwise",
|
|
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
|
|
"documents the apps routes and every field of the app view in the Swagger spec",
|
|
"lists every registered addon route in the feature registry",
|
|
"gates the apps routes by authentication, feature and administration",
|
|
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
|
|
"refuses every management call of the owner itself for a caller that is not an administrator",
|
|
"saves, refreshes and removes a library by reference and leaves installed addons alone",
|
|
"upgrades an installed addon through the typed action and keeps its earlier generation",
|
|
"reports a lost source change as an unknown outcome and a lost read as unavailable",
|
|
"documents the management actions and every emitted field of the installed view",
|
|
"serves the declared files of the current package through every frontend with immutable headers",
|
|
"lists the same URLs the route serves, and only for an enabled addon",
|
|
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
|
|
"accepts a same-origin browser session and refuses a cross-site or direct one",
|
|
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
|
|
"refuses a declared file that is not a regular file of the package",
|
|
"documents the asset route and its binary response in the Swagger spec",
|
|
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
|
|
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
|
|
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
|
|
"checks only for an administrator's own browser session, and applies nothing",
|
|
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
|
|
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
|
|
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
|
|
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
|
|
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
|
|
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend",
|
|
"returns the SDK refusal text to the administrator and the generic message for an unrelated failure",
|
|
"returns the same text through a forwarding frontend"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"artifacts": {
|
|
"kind": "ginkgo",
|
|
"commands": [
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/services/addons/artifacts",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/artifacts.json"
|
|
],
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/services/addons/gateway",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/artifacts-gateway.json"
|
|
],
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/http/endpoints/addons",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/artifacts-http.json"
|
|
]
|
|
],
|
|
"cases": [
|
|
"adopts every output of a result or none, and shows the owner only its own status",
|
|
"sanitizes attachment names and maps media types to a fixed allowlist",
|
|
"applies finite default limits and rejects partial or unbounded overrides",
|
|
"keeps staged bytes behind the object store boundary and publishes only complete writes",
|
|
"never serves an artifact at or after expiry, including during admission and mid-stream",
|
|
"fails a transfer that outlives its artifact",
|
|
"fails a transfer whose source is revoked before completion and denies a revoked download",
|
|
"stops a download stream when the source is revoked mid-stream",
|
|
"requires read access to every source resource at completion and download",
|
|
"denies a disabled or unavailable account at ingestion and download",
|
|
"denies downloads of a disabled addon, keeps the bytes and serves again only while unexpired with current permissions",
|
|
"denies downloads after uninstall and removes the bytes at the next sweep",
|
|
"sweeps expired artifacts, abandoned partials and orphan files without touching live transfers",
|
|
"enforces per-user, total and size limits atomically under concurrent ingestion",
|
|
"bounds concurrent transfers and concurrent downloads",
|
|
"cancels a transfer by its context or by its owner and removes the partial bytes",
|
|
"returns the same artifact for a repeated request without a second transfer",
|
|
"keeps addon handles operation-bound and out of metadata and views",
|
|
"keeps complete artifacts across a restart and settles interrupted transfers",
|
|
"keeps the bytes of a transfer that completes while a sweep is running",
|
|
"never loses the bytes of a complete artifact when sweeps race with several completing transfers",
|
|
"answers a transient storage error as unavailable and keeps the bytes and the record",
|
|
"marks an artifact corrupt only for missing bytes or a size mismatch",
|
|
"answers a download that races with an expiry or a drop like any expired identifier",
|
|
"refuses a corrupt metadata store and stops writing after a failed sync",
|
|
"waits for background transfers before Close returns and writes nothing after",
|
|
"ingests a file result into a private staged artifact with a host-generated identifier",
|
|
"never uses an addon handle, URL or path as an identifier or a file path",
|
|
"answers one denial for an unknown identifier and for another principal's artifact",
|
|
"never serves incomplete, short, long or failed transfers and removes their partial bytes",
|
|
"streams ingestion and download without buffering the whole file",
|
|
"rejects an output declared larger than one artifact may be before reading it",
|
|
"never opens an output for a request that names a tool no source declares",
|
|
"denies an output request whose arguments repeat a key and never opens the output",
|
|
"reports an unavailable declaration source as unavailable and never opens the output",
|
|
"shortens the lifetime and keeps the bounds consistent, and zero keeps the defaults",
|
|
"fails the artifact with a fixed reason that says it was refused, not that the add-on is down",
|
|
"serves only declared installed generation assets and rejects traversal",
|
|
"fails closed without current identity or resource policy and reports the original ID of an unknown mutation outcome",
|
|
"reports an unclassified account check error as unavailable on every path and a wrapped denial as forbidden",
|
|
"propagates interrupted progress cancellation through the receiving frontend",
|
|
"validates finite relay budgets and prevents disabling polling bounds",
|
|
"builds a carrier only from complete pinned identities",
|
|
"types an unknown mutation outcome as unavailable without losing its operation",
|
|
"rejects untrusted peers wrong audience body expiry replay and revoked credentials",
|
|
"alternates pinned frontends and rejects untrusted certificates without local fallback",
|
|
"reports the original operation after lost mutation replies without retrying",
|
|
"rejects a stream longer than its receiving frontend budget",
|
|
"rejects a CA signed peer without a pin on the owner side",
|
|
"refuses an owner whose CA signed certificate is not the pinned owner",
|
|
"returns the artifact status through the owner from every frontend with one denial for the rest",
|
|
"types the owner's refusal and outage of a lookup the same from every frontend",
|
|
"writes an attachment header that cannot be broken out of",
|
|
"rotates the enforced audience on restart and rejects captured requests",
|
|
"never expires the response deadline after the relay returned",
|
|
"returns the owner's forbidden status for an invalid kind and for missing policy",
|
|
"still reports unavailable when the owner is unable to serve and not forbidden",
|
|
"reaches the same decision through both frontends and delivers bytes when allowed",
|
|
"keeps aborting when revocation happens after bytes were written",
|
|
"bounds progress, asset and file relays by their own limit",
|
|
"alternates real owner journal status and terminates coarse progress without submitting again",
|
|
"reports an account store outage as unavailable and a refused account as forbidden",
|
|
"rejects unknown lifecycle argument fields before touching the owner journal",
|
|
"reports a runtime that cannot serve as unavailable through both frontends",
|
|
"reports an output that ends before its first byte as unavailable",
|
|
"fails closed as unavailable for an unclassified owner error",
|
|
"keeps authorization and policy denials forbidden",
|
|
"keeps a mutation unknown when the runtime fails after the owner applied it",
|
|
"keeps a mutation unknown when the owner reports recovery required for its operation",
|
|
"reports a mutation as unknown when the owner cannot serve it at all",
|
|
"keeps a mutation unknown on the owner's own frontend and leaves reads and denials alone",
|
|
"lets unavailability win when an error wraps both a denial and an unavailable cause",
|
|
"does not leak attachment headers into an error when the first read fails",
|
|
"treats every action except the known reads as a mutation",
|
|
"keeps resolved resources under admission for JSON and attachment bytes",
|
|
"closes interrupted output and releases admission on disconnect",
|
|
"rechecks revoked credentials during attachment copying",
|
|
"adopts read outputs as private artifacts inside admission and replaces a forged resource identity",
|
|
"refuses at ingest a file result larger than the relay file bound so nothing unservable is staged",
|
|
"denies private relays without host resolution and admission",
|
|
"serves declared assets of the current enabled generation by package digest only",
|
|
"allows only an exact declared tool name and fails closed otherwise",
|
|
"never contacts the add-on for an undeclared tool and still serves a declared one",
|
|
"denies a repeated key at any depth however it is spelled",
|
|
"denies arguments that are not exactly one object",
|
|
"separates a denial from an unavailable declaration source",
|
|
"answers 503 and never contacts the add-on when the source is unavailable or the arguments repeat a key",
|
|
"is the typed invalid request on the owner for a read, never an outage",
|
|
"is the typed invalid request on the owner for a proposal call",
|
|
"is the typed invalid request on the owner for a json relay",
|
|
"is the same typed answer from a forwarding frontend",
|
|
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
|
|
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
|
|
"denies sharing and deletion proposals and an unauthenticated caller",
|
|
"serves the local owner's confirmation only from a same-origin fetch of the host page",
|
|
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
|
|
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
|
|
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
|
|
"tells an editor of a blocked write only that it is denied",
|
|
"returns the applied proposal when the confirmed operation committed",
|
|
"answers an owner outage by the owner's state with the same type from every frontend",
|
|
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
|
|
"documents the proposal routes and the proposal schema in the Swagger spec",
|
|
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
|
|
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
|
|
"checks browser CSRF feature and admin access with real stored keys",
|
|
"serves a private file result as a safe attachment over real HTTP",
|
|
"never renders hostile names or active media types inline",
|
|
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
|
|
"denies the download of a disabled addon and serves it again after enable",
|
|
"relays the same bytes, headers and denials through two forwarding frontends",
|
|
"keeps a file result of a read denied whole without an artifact store",
|
|
"serves the local owner's file only in local-owner mode",
|
|
"documents the artifact routes and the artifact schema in the Swagger spec",
|
|
"rejects anonymous callers and forged forwarding headers",
|
|
"gates the feature and then administration for named keys",
|
|
"requires same-origin browser requests for cookie mutations",
|
|
"registers only the dispatch, relay and proposal mutations",
|
|
"reserves every first path segment the host registers under /api/addons",
|
|
"gates the artifact routes by authentication and feature",
|
|
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
|
|
"rejects anonymous and forged forwarding authority through real authentication",
|
|
"lets callers through only when the deployment selected local-owner mode",
|
|
"keeps authentication, the feature gate and administration when accounts exist",
|
|
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
|
|
"documents every field the error responses emit in the Swagger schema",
|
|
"reports an unavailable read as plain unavailability",
|
|
"reports a denial as forbidden",
|
|
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
|
|
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
|
|
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
|
|
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
|
|
"serves the verified icon through the host route and denies it identically otherwise",
|
|
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
|
|
"documents the apps routes and every field of the app view in the Swagger spec",
|
|
"lists every registered addon route in the feature registry",
|
|
"gates the apps routes by authentication, feature and administration",
|
|
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
|
|
"refuses every management call of the owner itself for a caller that is not an administrator",
|
|
"saves, refreshes and removes a library by reference and leaves installed addons alone",
|
|
"upgrades an installed addon through the typed action and keeps its earlier generation",
|
|
"reports a lost source change as an unknown outcome and a lost read as unavailable",
|
|
"documents the management actions and every emitted field of the installed view",
|
|
"serves the declared files of the current package through every frontend with immutable headers",
|
|
"lists the same URLs the route serves, and only for an enabled addon",
|
|
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
|
|
"accepts a same-origin browser session and refuses a cross-site or direct one",
|
|
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
|
|
"refuses a declared file that is not a regular file of the package",
|
|
"documents the asset route and its binary response in the Swagger spec",
|
|
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
|
|
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
|
|
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
|
|
"checks only for an administrator's own browser session, and applies nothing",
|
|
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
|
|
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
|
|
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
|
|
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
|
|
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
|
|
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend"
|
|
],
|
|
"report": ".cache/addons/logs/artifacts.json",
|
|
"reports": [
|
|
{
|
|
"path": ".cache/addons/logs/artifacts.json",
|
|
"cases": [
|
|
"adopts every output of a result or none, and shows the owner only its own status",
|
|
"sanitizes attachment names and maps media types to a fixed allowlist",
|
|
"applies finite default limits and rejects partial or unbounded overrides",
|
|
"keeps staged bytes behind the object store boundary and publishes only complete writes",
|
|
"never serves an artifact at or after expiry, including during admission and mid-stream",
|
|
"fails a transfer that outlives its artifact",
|
|
"fails a transfer whose source is revoked before completion and denies a revoked download",
|
|
"stops a download stream when the source is revoked mid-stream",
|
|
"requires read access to every source resource at completion and download",
|
|
"denies a disabled or unavailable account at ingestion and download",
|
|
"denies downloads of a disabled addon, keeps the bytes and serves again only while unexpired with current permissions",
|
|
"denies downloads after uninstall and removes the bytes at the next sweep",
|
|
"sweeps expired artifacts, abandoned partials and orphan files without touching live transfers",
|
|
"enforces per-user, total and size limits atomically under concurrent ingestion",
|
|
"bounds concurrent transfers and concurrent downloads",
|
|
"cancels a transfer by its context or by its owner and removes the partial bytes",
|
|
"returns the same artifact for a repeated request without a second transfer",
|
|
"keeps addon handles operation-bound and out of metadata and views",
|
|
"keeps complete artifacts across a restart and settles interrupted transfers",
|
|
"keeps the bytes of a transfer that completes while a sweep is running",
|
|
"never loses the bytes of a complete artifact when sweeps race with several completing transfers",
|
|
"answers a transient storage error as unavailable and keeps the bytes and the record",
|
|
"marks an artifact corrupt only for missing bytes or a size mismatch",
|
|
"answers a download that races with an expiry or a drop like any expired identifier",
|
|
"refuses a corrupt metadata store and stops writing after a failed sync",
|
|
"waits for background transfers before Close returns and writes nothing after",
|
|
"ingests a file result into a private staged artifact with a host-generated identifier",
|
|
"never uses an addon handle, URL or path as an identifier or a file path",
|
|
"answers one denial for an unknown identifier and for another principal's artifact",
|
|
"never serves incomplete, short, long or failed transfers and removes their partial bytes",
|
|
"streams ingestion and download without buffering the whole file",
|
|
"rejects an output declared larger than one artifact may be before reading it",
|
|
"never opens an output for a request that names a tool no source declares",
|
|
"denies an output request whose arguments repeat a key and never opens the output",
|
|
"reports an unavailable declaration source as unavailable and never opens the output",
|
|
"shortens the lifetime and keeps the bounds consistent, and zero keeps the defaults",
|
|
"fails the artifact with a fixed reason that says it was refused, not that the add-on is down"
|
|
]
|
|
},
|
|
{
|
|
"path": ".cache/addons/logs/artifacts-gateway.json",
|
|
"cases": [
|
|
"serves only declared installed generation assets and rejects traversal",
|
|
"fails closed without current identity or resource policy and reports the original ID of an unknown mutation outcome",
|
|
"reports an unclassified account check error as unavailable on every path and a wrapped denial as forbidden",
|
|
"propagates interrupted progress cancellation through the receiving frontend",
|
|
"validates finite relay budgets and prevents disabling polling bounds",
|
|
"builds a carrier only from complete pinned identities",
|
|
"types an unknown mutation outcome as unavailable without losing its operation",
|
|
"rejects untrusted peers wrong audience body expiry replay and revoked credentials",
|
|
"alternates pinned frontends and rejects untrusted certificates without local fallback",
|
|
"reports the original operation after lost mutation replies without retrying",
|
|
"rejects a stream longer than its receiving frontend budget",
|
|
"rejects a CA signed peer without a pin on the owner side",
|
|
"refuses an owner whose CA signed certificate is not the pinned owner",
|
|
"returns the artifact status through the owner from every frontend with one denial for the rest",
|
|
"types the owner's refusal and outage of a lookup the same from every frontend",
|
|
"writes an attachment header that cannot be broken out of",
|
|
"rotates the enforced audience on restart and rejects captured requests",
|
|
"never expires the response deadline after the relay returned",
|
|
"returns the owner's forbidden status for an invalid kind and for missing policy",
|
|
"still reports unavailable when the owner is unable to serve and not forbidden",
|
|
"reaches the same decision through both frontends and delivers bytes when allowed",
|
|
"keeps aborting when revocation happens after bytes were written",
|
|
"bounds progress, asset and file relays by their own limit",
|
|
"alternates real owner journal status and terminates coarse progress without submitting again",
|
|
"reports an account store outage as unavailable and a refused account as forbidden",
|
|
"rejects unknown lifecycle argument fields before touching the owner journal",
|
|
"reports a runtime that cannot serve as unavailable through both frontends",
|
|
"reports an output that ends before its first byte as unavailable",
|
|
"fails closed as unavailable for an unclassified owner error",
|
|
"keeps authorization and policy denials forbidden",
|
|
"keeps a mutation unknown when the runtime fails after the owner applied it",
|
|
"keeps a mutation unknown when the owner reports recovery required for its operation",
|
|
"reports a mutation as unknown when the owner cannot serve it at all",
|
|
"keeps a mutation unknown on the owner's own frontend and leaves reads and denials alone",
|
|
"lets unavailability win when an error wraps both a denial and an unavailable cause",
|
|
"does not leak attachment headers into an error when the first read fails",
|
|
"treats every action except the known reads as a mutation",
|
|
"keeps resolved resources under admission for JSON and attachment bytes",
|
|
"closes interrupted output and releases admission on disconnect",
|
|
"rechecks revoked credentials during attachment copying",
|
|
"adopts read outputs as private artifacts inside admission and replaces a forged resource identity",
|
|
"refuses at ingest a file result larger than the relay file bound so nothing unservable is staged",
|
|
"denies private relays without host resolution and admission",
|
|
"serves declared assets of the current enabled generation by package digest only",
|
|
"allows only an exact declared tool name and fails closed otherwise",
|
|
"never contacts the add-on for an undeclared tool and still serves a declared one",
|
|
"denies a repeated key at any depth however it is spelled",
|
|
"denies arguments that are not exactly one object",
|
|
"separates a denial from an unavailable declaration source",
|
|
"answers 503 and never contacts the add-on when the source is unavailable or the arguments repeat a key",
|
|
"is the typed invalid request on the owner for a read, never an outage",
|
|
"is the typed invalid request on the owner for a proposal call",
|
|
"is the typed invalid request on the owner for a json relay",
|
|
"is the same typed answer from a forwarding frontend"
|
|
]
|
|
},
|
|
{
|
|
"path": ".cache/addons/logs/artifacts-http.json",
|
|
"cases": [
|
|
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
|
|
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
|
|
"denies sharing and deletion proposals and an unauthenticated caller",
|
|
"serves the local owner's confirmation only from a same-origin fetch of the host page",
|
|
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
|
|
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
|
|
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
|
|
"tells an editor of a blocked write only that it is denied",
|
|
"returns the applied proposal when the confirmed operation committed",
|
|
"answers an owner outage by the owner's state with the same type from every frontend",
|
|
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
|
|
"documents the proposal routes and the proposal schema in the Swagger spec",
|
|
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
|
|
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
|
|
"checks browser CSRF feature and admin access with real stored keys",
|
|
"serves a private file result as a safe attachment over real HTTP",
|
|
"never renders hostile names or active media types inline",
|
|
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
|
|
"denies the download of a disabled addon and serves it again after enable",
|
|
"relays the same bytes, headers and denials through two forwarding frontends",
|
|
"keeps a file result of a read denied whole without an artifact store",
|
|
"serves the local owner's file only in local-owner mode",
|
|
"documents the artifact routes and the artifact schema in the Swagger spec",
|
|
"rejects anonymous callers and forged forwarding headers",
|
|
"gates the feature and then administration for named keys",
|
|
"requires same-origin browser requests for cookie mutations",
|
|
"registers only the dispatch, relay and proposal mutations",
|
|
"reserves every first path segment the host registers under /api/addons",
|
|
"gates the artifact routes by authentication and feature",
|
|
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
|
|
"rejects anonymous and forged forwarding authority through real authentication",
|
|
"lets callers through only when the deployment selected local-owner mode",
|
|
"keeps authentication, the feature gate and administration when accounts exist",
|
|
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
|
|
"documents every field the error responses emit in the Swagger schema",
|
|
"reports an unavailable read as plain unavailability",
|
|
"reports a denial as forbidden",
|
|
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
|
|
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
|
|
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
|
|
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
|
|
"serves the verified icon through the host route and denies it identically otherwise",
|
|
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
|
|
"documents the apps routes and every field of the app view in the Swagger spec",
|
|
"lists every registered addon route in the feature registry",
|
|
"gates the apps routes by authentication, feature and administration",
|
|
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
|
|
"refuses every management call of the owner itself for a caller that is not an administrator",
|
|
"saves, refreshes and removes a library by reference and leaves installed addons alone",
|
|
"upgrades an installed addon through the typed action and keeps its earlier generation",
|
|
"reports a lost source change as an unknown outcome and a lost read as unavailable",
|
|
"documents the management actions and every emitted field of the installed view",
|
|
"serves the declared files of the current package through every frontend with immutable headers",
|
|
"lists the same URLs the route serves, and only for an enabled addon",
|
|
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
|
|
"accepts a same-origin browser session and refuses a cross-site or direct one",
|
|
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
|
|
"refuses a declared file that is not a regular file of the package",
|
|
"documents the asset route and its binary response in the Swagger spec",
|
|
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
|
|
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
|
|
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
|
|
"checks only for an administrator's own browser session, and applies nothing",
|
|
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
|
|
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
|
|
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
|
|
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
|
|
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
|
|
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend",
|
|
"returns the SDK refusal text to the administrator and the generic message for an unrelated failure",
|
|
"returns the same text through a forwarding frontend"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"apps": {
|
|
"kind": "ginkgo",
|
|
"commands": [
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/services/addons/apps",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/apps.json"
|
|
],
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/services/addons",
|
|
"-ginkgo.json-report=../../../.cache/addons/logs/apps-lifecycle.json"
|
|
],
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/services/addons/runtime",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/apps-runtime.json"
|
|
],
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./core/http/endpoints/addons",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/apps-http.json"
|
|
]
|
|
],
|
|
"cases": [
|
|
"lists installed enabled addons for users and adds installed disabled ones only for administrators",
|
|
"derives display fields, the main page and the icon URL from the verified manifest only",
|
|
"bounds the tool summary and coerces unknown process states to failed",
|
|
"shows controls and the management link only to administrators and never leaks owner details",
|
|
"describes the immutable UI assets of an enabled addon by the package digest and never otherwise",
|
|
"denies enable and disable for a stale generation without recording anything",
|
|
"lists the identifiers of installed addons, disabled ones included",
|
|
"refuses to list installed identifiers while recovery is required",
|
|
"lists apps by visibility and serves an icon only for a visible app at its generation",
|
|
"cancels status lookup while a lifecycle writer holds the journal lock",
|
|
"retries runtime synchronization after canceled disable and generation upgrade",
|
|
"rejects symlinked package roots without touching external staging",
|
|
"recovers every durable journal boundary without replaying publication",
|
|
"removes abandoned staging without removing published packages on recovery",
|
|
"keeps immutable history on successful upgrade and reinstallation",
|
|
"excludes competing owners and rejects conflicting durable identities",
|
|
"never opens replica roots or elects an absent owner",
|
|
"binds duplicate operation IDs to actor and command and serializes conflicts",
|
|
"refuses commands and asset reads for an add-on ID the host serves as a route",
|
|
"retains generations identity data and grants across uninstall and restart",
|
|
"preserves old packages and active generation on manager upgrade failure",
|
|
"requires current authoritative administration even for idempotent retries",
|
|
"executes enabled owner intent on startup and stops on disable and close without forwarder execution",
|
|
"binds lifecycle lookup to current admin and original actor without writes or repair",
|
|
"reports the supervisor state of an app through a crash and a restart",
|
|
"reads a flat directory in batches and stops at the entry bound",
|
|
"adds up nested files and reports a complete walk as not truncated",
|
|
"never follows or counts a symbolic link",
|
|
"keeps a result for a short time so polling does not walk again",
|
|
"stops at the time bound and reports a truncated size",
|
|
"does not keep a result cut short by the caller",
|
|
"is what the installed view reports for the data directory",
|
|
"resolves a package for the current enabled generation and digest only",
|
|
"answers from the current installed manifest only and follows a generation change",
|
|
"reports a digest-only change of a moving channel, applies nothing and offers the pinned upgrade",
|
|
"refuses a second operation ID for the same transition, in flight or done, and applies it once",
|
|
"runs concurrent requests with one operation ID once and gives each the same answer",
|
|
"serializes conflicting upgrades by the installed digest and refuses the loser without a record",
|
|
"refuses a candidate that is not the one the library resolves now",
|
|
"refuses an upgrade to the digest that is already installed",
|
|
"rechecks compatibility at execution and refuses an incompatible candidate",
|
|
"selects a newer immutable version and treats a rewritten version as an integrity error",
|
|
"keeps the last good generation when the candidate cannot be staged",
|
|
"never switches the library or channel, and a failed check is never up to date",
|
|
"lets an administrator refresh and everyone with the feature read a redacted status",
|
|
"shows the pending update in the apps list from the cache only",
|
|
"does not accept pins without an update checker or on another action",
|
|
"keeps the unpinned typed upgrade of an earlier release working",
|
|
"registers only ready generation bound service headless and UI capabilities",
|
|
"rejects forged registration nonloopback and stale incarnation handshakes",
|
|
"bounds readiness and handles exit during start and stop",
|
|
"withdraws immediately drains boundedly and rejects stale process identities",
|
|
"exhausts restart budget without retaining dead registrations",
|
|
"does not inherit secrets and exits when the private parent channel closes",
|
|
"fails closed on ambiguous launch identities and preserves unrelated reused PIDs",
|
|
"retains a canceled restart slot until cleanup completes and rejects duplicate supervisors",
|
|
"rejects nonloopback endpoints and bounds oversized streams and concurrency",
|
|
"reports stopped, running, failed, starting and running again across a crash and a restart",
|
|
"keeps reporting failed once the restart budget is exhausted",
|
|
"rejects foreign supervisor handles and numeric PID substitutions",
|
|
"resets restart budget only after sustained authenticated health",
|
|
"kills the exact paused child of a killed owner before launching its replacement",
|
|
"never reports failed between a launch starting and the restarted process being published",
|
|
"reserves a draining slot against concurrent starts",
|
|
"waits for a restart launch worker before acknowledging stop",
|
|
"exposes a new incarnation client after restart without reviving the old client",
|
|
"refuses a missing established ledger and fences failed cleanup publication",
|
|
"authenticates every request and separates trusted authority from model arguments",
|
|
"bounds output streams cancellation deadlines and stop admission",
|
|
"tells a 409 conflict of the add-on from an outage",
|
|
"withdraws and initiates every live slot before a cleanup timeout",
|
|
"creates one private data directory per addon and passes its path in the startup object",
|
|
"gives no data directory without a data root and refuses an unsafe root or addon ID",
|
|
"gives an add-on that the host setting names a host endpoint of its own",
|
|
"gives an add-on that the host setting does not name no host endpoint",
|
|
"closes the host endpoint when the incarnation ends",
|
|
"an HTTP 400 answer",
|
|
"an HTTP 422 answer",
|
|
"keeps a bounded, printable reason and nothing else of the body",
|
|
"leaves 503, 500 and 404 as outages",
|
|
"rejects anonymous and forged forwarding authority through real authentication",
|
|
"lets callers through only when the deployment selected local-owner mode",
|
|
"keeps authentication, the feature gate and administration when accounts exist",
|
|
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
|
|
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
|
|
"serves the verified icon through the host route and denies it identically otherwise",
|
|
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
|
|
"documents the apps routes and every field of the app view in the Swagger spec",
|
|
"rejects anonymous callers and forged forwarding headers",
|
|
"gates the feature and then administration for named keys",
|
|
"requires same-origin browser requests for cookie mutations",
|
|
"registers only the dispatch, relay and proposal mutations",
|
|
"reserves every first path segment the host registers under /api/addons",
|
|
"gates the artifact routes by authentication and feature",
|
|
"lists every registered addon route in the feature registry",
|
|
"gates the apps routes by authentication, feature and administration",
|
|
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
|
|
"checks browser CSRF feature and admin access with real stored keys",
|
|
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
|
|
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
|
|
"denies sharing and deletion proposals and an unauthenticated caller",
|
|
"serves the local owner's confirmation only from a same-origin fetch of the host page",
|
|
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
|
|
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
|
|
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
|
|
"tells an editor of a blocked write only that it is denied",
|
|
"returns the applied proposal when the confirmed operation committed",
|
|
"answers an owner outage by the owner's state with the same type from every frontend",
|
|
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
|
|
"documents the proposal routes and the proposal schema in the Swagger spec",
|
|
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
|
|
"documents every field the error responses emit in the Swagger schema",
|
|
"reports an unavailable read as plain unavailability",
|
|
"reports a denial as forbidden",
|
|
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
|
|
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
|
|
"serves a private file result as a safe attachment over real HTTP",
|
|
"never renders hostile names or active media types inline",
|
|
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
|
|
"denies the download of a disabled addon and serves it again after enable",
|
|
"relays the same bytes, headers and denials through two forwarding frontends",
|
|
"keeps a file result of a read denied whole without an artifact store",
|
|
"serves the local owner's file only in local-owner mode",
|
|
"documents the artifact routes and the artifact schema in the Swagger spec",
|
|
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
|
|
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
|
|
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
|
|
"refuses every management call of the owner itself for a caller that is not an administrator",
|
|
"saves, refreshes and removes a library by reference and leaves installed addons alone",
|
|
"upgrades an installed addon through the typed action and keeps its earlier generation",
|
|
"reports a lost source change as an unknown outcome and a lost read as unavailable",
|
|
"documents the management actions and every emitted field of the installed view",
|
|
"serves the declared files of the current package through every frontend with immutable headers",
|
|
"lists the same URLs the route serves, and only for an enabled addon",
|
|
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
|
|
"accepts a same-origin browser session and refuses a cross-site or direct one",
|
|
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
|
|
"refuses a declared file that is not a regular file of the package",
|
|
"documents the asset route and its binary response in the Swagger spec",
|
|
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
|
|
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
|
|
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
|
|
"checks only for an administrator's own browser session, and applies nothing",
|
|
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
|
|
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
|
|
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
|
|
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
|
|
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
|
|
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend",
|
|
"types a withdrawn client, a full slot table, a bad envelope and a missing schema as not sent",
|
|
"keeps a not-sent error an ErrRuntime for callers that do not tell them apart",
|
|
"types a refused connection as not sent",
|
|
"never types a possibly-sent request as not sent",
|
|
"carries the SDK refusal text to the caller of a failed install and keeps the generic error",
|
|
"installs an add-on whose SDK range contains the host SDK",
|
|
"returns the SDK refusal text to the administrator and the generic message for an unrelated failure",
|
|
"returns the same text through a forwarding frontend"
|
|
],
|
|
"report": ".cache/addons/logs/apps.json",
|
|
"reports": [
|
|
{
|
|
"path": ".cache/addons/logs/apps.json",
|
|
"cases": [
|
|
"lists installed enabled addons for users and adds installed disabled ones only for administrators",
|
|
"derives display fields, the main page and the icon URL from the verified manifest only",
|
|
"bounds the tool summary and coerces unknown process states to failed",
|
|
"shows controls and the management link only to administrators and never leaks owner details",
|
|
"describes the immutable UI assets of an enabled addon by the package digest and never otherwise"
|
|
]
|
|
},
|
|
{
|
|
"path": ".cache/addons/logs/apps-lifecycle.json",
|
|
"cases": [
|
|
"denies enable and disable for a stale generation without recording anything",
|
|
"lists the identifiers of installed addons, disabled ones included",
|
|
"refuses to list installed identifiers while recovery is required",
|
|
"lists apps by visibility and serves an icon only for a visible app at its generation",
|
|
"cancels status lookup while a lifecycle writer holds the journal lock",
|
|
"retries runtime synchronization after canceled disable and generation upgrade",
|
|
"rejects symlinked package roots without touching external staging",
|
|
"recovers every durable journal boundary without replaying publication",
|
|
"removes abandoned staging without removing published packages on recovery",
|
|
"keeps immutable history on successful upgrade and reinstallation",
|
|
"excludes competing owners and rejects conflicting durable identities",
|
|
"never opens replica roots or elects an absent owner",
|
|
"binds duplicate operation IDs to actor and command and serializes conflicts",
|
|
"refuses commands and asset reads for an add-on ID the host serves as a route",
|
|
"retains generations identity data and grants across uninstall and restart",
|
|
"preserves old packages and active generation on manager upgrade failure",
|
|
"requires current authoritative administration even for idempotent retries",
|
|
"executes enabled owner intent on startup and stops on disable and close without forwarder execution",
|
|
"binds lifecycle lookup to current admin and original actor without writes or repair",
|
|
"reports the supervisor state of an app through a crash and a restart",
|
|
"reads a flat directory in batches and stops at the entry bound",
|
|
"adds up nested files and reports a complete walk as not truncated",
|
|
"never follows or counts a symbolic link",
|
|
"keeps a result for a short time so polling does not walk again",
|
|
"stops at the time bound and reports a truncated size",
|
|
"does not keep a result cut short by the caller",
|
|
"is what the installed view reports for the data directory",
|
|
"resolves a package for the current enabled generation and digest only",
|
|
"answers from the current installed manifest only and follows a generation change",
|
|
"reports a digest-only change of a moving channel, applies nothing and offers the pinned upgrade",
|
|
"refuses a second operation ID for the same transition, in flight or done, and applies it once",
|
|
"runs concurrent requests with one operation ID once and gives each the same answer",
|
|
"serializes conflicting upgrades by the installed digest and refuses the loser without a record",
|
|
"refuses a candidate that is not the one the library resolves now",
|
|
"refuses an upgrade to the digest that is already installed",
|
|
"rechecks compatibility at execution and refuses an incompatible candidate",
|
|
"selects a newer immutable version and treats a rewritten version as an integrity error",
|
|
"keeps the last good generation when the candidate cannot be staged",
|
|
"never switches the library or channel, and a failed check is never up to date",
|
|
"lets an administrator refresh and everyone with the feature read a redacted status",
|
|
"shows the pending update in the apps list from the cache only",
|
|
"does not accept pins without an update checker or on another action",
|
|
"keeps the unpinned typed upgrade of an earlier release working",
|
|
"carries the SDK refusal text to the caller of a failed install and keeps the generic error",
|
|
"installs an add-on whose SDK range contains the host SDK"
|
|
]
|
|
},
|
|
{
|
|
"path": ".cache/addons/logs/apps-runtime.json",
|
|
"cases": [
|
|
"registers only ready generation bound service headless and UI capabilities",
|
|
"rejects forged registration nonloopback and stale incarnation handshakes",
|
|
"bounds readiness and handles exit during start and stop",
|
|
"withdraws immediately drains boundedly and rejects stale process identities",
|
|
"exhausts restart budget without retaining dead registrations",
|
|
"does not inherit secrets and exits when the private parent channel closes",
|
|
"fails closed on ambiguous launch identities and preserves unrelated reused PIDs",
|
|
"retains a canceled restart slot until cleanup completes and rejects duplicate supervisors",
|
|
"rejects nonloopback endpoints and bounds oversized streams and concurrency",
|
|
"reports stopped, running, failed, starting and running again across a crash and a restart",
|
|
"keeps reporting failed once the restart budget is exhausted",
|
|
"rejects foreign supervisor handles and numeric PID substitutions",
|
|
"resets restart budget only after sustained authenticated health",
|
|
"kills the exact paused child of a killed owner before launching its replacement",
|
|
"never reports failed between a launch starting and the restarted process being published",
|
|
"reserves a draining slot against concurrent starts",
|
|
"waits for a restart launch worker before acknowledging stop",
|
|
"exposes a new incarnation client after restart without reviving the old client",
|
|
"refuses a missing established ledger and fences failed cleanup publication",
|
|
"authenticates every request and separates trusted authority from model arguments",
|
|
"bounds output streams cancellation deadlines and stop admission",
|
|
"tells a 409 conflict of the add-on from an outage",
|
|
"withdraws and initiates every live slot before a cleanup timeout",
|
|
"creates one private data directory per addon and passes its path in the startup object",
|
|
"gives no data directory without a data root and refuses an unsafe root or addon ID",
|
|
"gives an add-on that the host setting names a host endpoint of its own",
|
|
"gives an add-on that the host setting does not name no host endpoint",
|
|
"closes the host endpoint when the incarnation ends",
|
|
"an HTTP 400 answer",
|
|
"an HTTP 422 answer",
|
|
"keeps a bounded, printable reason and nothing else of the body",
|
|
"leaves 503, 500 and 404 as outages",
|
|
"types a withdrawn client, a full slot table, a bad envelope and a missing schema as not sent",
|
|
"keeps a not-sent error an ErrRuntime for callers that do not tell them apart",
|
|
"types a refused connection as not sent",
|
|
"never types a possibly-sent request as not sent"
|
|
]
|
|
},
|
|
{
|
|
"path": ".cache/addons/logs/apps-http.json",
|
|
"cases": [
|
|
"rejects anonymous and forged forwarding authority through real authentication",
|
|
"lets callers through only when the deployment selected local-owner mode",
|
|
"keeps authentication, the feature gate and administration when accounts exist",
|
|
"lists the enabled installed apps for a reader and the disabled ones too for administrators, the same from every frontend",
|
|
"lets only administrators start and stop, through the lifecycle manager, and denies a stale generation",
|
|
"serves the verified icon through the host route and denies it identically otherwise",
|
|
"reports a lost start as an unknown outcome with its original operation and a lost list as unavailable",
|
|
"documents the apps routes and every field of the app view in the Swagger spec",
|
|
"rejects anonymous callers and forged forwarding headers",
|
|
"gates the feature and then administration for named keys",
|
|
"requires same-origin browser requests for cookie mutations",
|
|
"registers only the dispatch, relay and proposal mutations",
|
|
"reserves every first path segment the host registers under /api/addons",
|
|
"gates the artifact routes by authentication and feature",
|
|
"lists every registered addon route in the feature registry",
|
|
"gates the apps routes by authentication, feature and administration",
|
|
"gates the proposal routes by feature and refuses a confirmation from a key before the owner is asked",
|
|
"checks browser CSRF feature and admin access with real stored keys",
|
|
"stores a proposal from an API key and lets only the proposer's browser session confirm it",
|
|
"cancels a proposal from the same chain and never lets typed dispatch or relay confirm",
|
|
"denies sharing and deletion proposals and an unauthenticated caller",
|
|
"serves the local owner's confirmation only from a same-origin fetch of the host page",
|
|
"reports a lost reply with the original operation from forwarding frontends and resolves it by receipt",
|
|
"lets only the resource owner's browser session abandon an unresolved outcome and then accepts writes",
|
|
"lets the owner role list an editor's unresolved proposal and abandon it by the listed digest from every frontend",
|
|
"tells an editor of a blocked write only that it is denied",
|
|
"returns the applied proposal when the confirmed operation committed",
|
|
"answers an owner outage by the owner's state with the same type from every frontend",
|
|
"keeps a proposal confirmable by the same ID after the owner could not reach the addon",
|
|
"documents the proposal routes and the proposal schema in the Swagger spec",
|
|
"reports an unknown mutation outcome from a forwarding frontend with the original operation",
|
|
"documents every field the error responses emit in the Swagger schema",
|
|
"reports an unavailable read as plain unavailability",
|
|
"reports a denial as forbidden",
|
|
"reports an unclassified account check error as unavailable and a definite denial as forbidden",
|
|
"reports an unknown mutation outcome from the owner's own frontend with the original operation",
|
|
"serves a private file result as a safe attachment over real HTTP",
|
|
"never renders hostile names or active media types inline",
|
|
"answers one 403 for unknown, foreign, incomplete and expired artifacts and requires the feature and a principal",
|
|
"denies the download of a disabled addon and serves it again after enable",
|
|
"relays the same bytes, headers and denials through two forwarding frontends",
|
|
"keeps a file result of a read denied whole without an artifact store",
|
|
"serves the local owner's file only in local-owner mode",
|
|
"documents the artifact routes and the artifact schema in the Swagger spec",
|
|
"serves one owner journal through two real authenticated HTTP frontends and rejects paused keys",
|
|
"serves the synthetic owner through the real chain, denies sharing and rejects named callers",
|
|
"serves catalog search, details and the installed management view to administrators only, the same from every frontend",
|
|
"refuses every management call of the owner itself for a caller that is not an administrator",
|
|
"saves, refreshes and removes a library by reference and leaves installed addons alone",
|
|
"upgrades an installed addon through the typed action and keeps its earlier generation",
|
|
"reports a lost source change as an unknown outcome and a lost read as unavailable",
|
|
"documents the management actions and every emitted field of the installed view",
|
|
"serves the declared files of the current package through every frontend with immutable headers",
|
|
"lists the same URLs the route serves, and only for an enabled addon",
|
|
"denies every other path, digest, addon and credential form with one answer and no immutable caching",
|
|
"accepts a same-origin browser session and refuses a cross-site or direct one",
|
|
"withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
|
|
"refuses a declared file that is not a regular file of the package",
|
|
"documents the asset route and its binary response in the Swagger spec",
|
|
"gives the same 403 on the owner and on a forwarding frontend and never contacts the add-on",
|
|
"lists the caller's own pending proposals the same from the owner and every forwarding frontend",
|
|
"gives every caller with the feature the same status from every frontend, redacted for non-administrators",
|
|
"checks only for an administrator's own browser session, and applies nothing",
|
|
"upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
|
|
"runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
|
|
"refuses an incompatible candidate and a library that cannot be read, with a typed answer",
|
|
"reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
|
|
"keeps the update actions out of the tools and names every field of the status in the Swagger spec",
|
|
"answers an add-on's invalid-request refusal as a typed 400 from the owner and from a forwarding frontend",
|
|
"returns the SDK refusal text to the administrator and the generic message for an unrelated failure",
|
|
"returns the same text through a forwarding frontend"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"gallery-ui": {
|
|
"kind": "shell",
|
|
"commands": [
|
|
[
|
|
"sh",
|
|
"scripts/addons/gallery_ui.sh"
|
|
]
|
|
],
|
|
"cases": [
|
|
"unit: query normalization bounds text, library and page",
|
|
"unit: an operation book keeps one identity per action until it is done",
|
|
"unit: responses classify the same way everywhere",
|
|
"unit: polling backs off on failure, slows when hidden and stays bounded",
|
|
"unit: library drafts accept references and refuse secrets before sending",
|
|
"unit: tabs: the server decides, the page only avoids showing what it will refuse",
|
|
"unit: app chips never turn an unknown state into running",
|
|
"unit: titles follow the language, then the default text, then the id",
|
|
"unit: update status comes only from an authoritative check",
|
|
"unit: the api sends one dispatch shape and classifies refusals",
|
|
"unit: an unknown outcome is read with the original identity and never resubmitted",
|
|
"unit: a denial is not retried and an exhausted read is reported as unknown",
|
|
"unit: an action book binds one identity to one click and its retries",
|
|
"unit: an action book mints a fresh identity once an action is resolved",
|
|
"unit: an action book blocks another action on a subject with an unknown outcome until it is resolved or dismissed",
|
|
"unit: a completed status that left the add-on unchanged is not reported as done",
|
|
"apps: lists enabled apps with state chips, the icon route and Open only for a main page",
|
|
"apps: a headless add-on shows its tools and no Open action",
|
|
"apps: a reader gets no start, stop, manage or management tabs",
|
|
"apps: an administrator starts an app with a fresh operation ID and the listed generation",
|
|
"apps: a lost start is read with the same operation ID and never submitted again",
|
|
"apps: an unknown start is resolved or dismissed before the next action and never replays its ID",
|
|
"apps: dismissing an unknown outcome lets the next click mint a new operation",
|
|
"apps: a completed status that left the app unchanged is not shown as done",
|
|
"apps: a refused start shows the server denial and refreshes the list",
|
|
"apps: the list refreshes on a bounded interval, backs off on errors and stops when left",
|
|
"apps: an add-on that contributes UI keeps the list current off the page and its disable stops the reads",
|
|
"apps: a viewer without the add-ons feature never requests the list",
|
|
"browse: searches the libraries, pages and shows trust and platform facts",
|
|
"browse: installing asks first and leaves the add-on disabled until it is enabled",
|
|
"installed: health is separate from enabled and the details show trust, compatibility and storage",
|
|
"installed: an update is shown only from the owner update field and upgrade sends that version",
|
|
"installed: uninstalling warns that data is kept before anything is submitted",
|
|
"installed: Escape cancels the uninstall dialog only, then closes the sheet, and focus returns",
|
|
"installed: an unknown enable blocks other actions on the add-on until it is read",
|
|
"installed: a headless add-on keeps its details, health and tools",
|
|
"installed: a refusal from the server is shown even though the tab was offered",
|
|
"libraries: a private library is saved by credential reference and never carries a secret",
|
|
"libraries: removing a library says installed add-ons stay and leaves them installed",
|
|
"libraries: a refresh reports its result and a failed fetch is shown as failed",
|
|
"keyboard: the tab list moves with the arrow keys and actions are reachable",
|
|
"narrow: at 400 px the apps page is one column without sideways scrolling",
|
|
"theme: the apps page follows the light and dark tokens",
|
|
"i18n: the page follows the interface language",
|
|
"hub: the Add-ons tab appears only for an account that holds the feature",
|
|
"regression: the backends catalog still searches, pages and shows its empty state"
|
|
]
|
|
},
|
|
"esm-ui": {
|
|
"kind": "shell",
|
|
"commands": [
|
|
[
|
|
"sh",
|
|
"scripts/addons/esm_ui.sh"
|
|
]
|
|
],
|
|
"cases": [
|
|
"unit: sdk: compatibility accepts only a range that holds the host SDK version",
|
|
"unit: sdk: the object is a frozen allowlist that carries the host React and no host internals",
|
|
"unit: sdk: hooks run on the host React instance and a wrapper keeps one component type",
|
|
"unit: sdk: icons outside the semantic set fall back and theme tokens are a fixed set",
|
|
"unit: sdk: navigation stays inside the add-on prefix and its declared pages",
|
|
"unit: sdk: api calls carry the add-on and its generation and nothing else is reachable",
|
|
"unit: sdk: after the signal aborts every service refuses and each disposer runs once",
|
|
"unit: sdk: markDirty reports unsaved edits once per change and notifications are bounded",
|
|
"unit: sdk: locale is scoped to the add-on and falls back to the default text",
|
|
"unit: sdk: layers are host wrappers with a bounded spec",
|
|
"unit: css: every selector is scoped to the add-on root and the global ones are neutralised",
|
|
"unit: css: imports, fonts, external urls and unknown at-rules are dropped and keyframes are renamed",
|
|
"unit: css: no value that loads a URL survives anywhere in the sheet",
|
|
"unit: css: harmless values, escapes in strings and nested rules are kept",
|
|
"unit: css: two add-ons that use the same class names get disjoint scopes",
|
|
"unit: loader: asset URLs must be same-origin immutable URLs of the add-on own package",
|
|
"unit: loader: an incompatible SDK range is never imported and leaves a clear error",
|
|
"unit: loader: the module receives only the host SDK, its result is validated and styles are scoped",
|
|
"unit: loader: a module without createAddon, with a bad result or a bare import is a load error",
|
|
"unit: loader: a hanging import times out and an abort cancels and cleans up",
|
|
"unit: loader: dispose runs once, aborts the SDK signal and removes the styles",
|
|
"unit: loader: chat actions are limited to declared ids and carry only the conversation context",
|
|
"unit: registry: disable, uninstall, crash and update withdraw a loaded add-on at once",
|
|
"unit: registry: unsaved edits keep a withdrawn add-on stale until the user reloads",
|
|
"unit: registry: a poll never replaces a withdrawn instance; only reload does",
|
|
"unit: registry: a hold ends with its last holder and a load that was withdrawn leaves no instance behind",
|
|
"unit: registry: navigation and chat actions come only from usable add-ons of the current generation",
|
|
"unit: registry: the Add-ons tab lists page links only when the registry has usable add-ons",
|
|
"unit: registry: the list is read off the Add-ons page only for a viewer with the feature and a UI contribution",
|
|
"go: describes the immutable UI assets of an enabled addon by the package digest and never otherwise",
|
|
"go: resolves a package for the current enabled generation and digest only",
|
|
"go: serves declared assets of the current enabled generation by package digest only",
|
|
"go: serves the declared files of the current package through every frontend with immutable headers",
|
|
"go: lists the same URLs the route serves, and only for an enabled addon",
|
|
"go: denies every other path, digest, addon and credential form with one answer and no immutable caching",
|
|
"go: accepts a same-origin browser session and refuses a cross-site or direct one",
|
|
"go: withdraws the code the moment the addon is disabled, uninstalled or replaced, even for a page that is still open",
|
|
"go: refuses a declared file that is not a regular file of the package",
|
|
"go: documents the asset route and its binary response in the Swagger spec",
|
|
"esm: a fixture add-on installed after the host build loads through real authorization and draws in its own root",
|
|
"esm: hooks run on the host React and the add-on keeps its state across renders",
|
|
"esm: the add-on style sheet is scoped to its root and leaves the host and other add-ons alone",
|
|
"esm: a component that throws is contained by the error boundary and the shell keeps working",
|
|
"esm: deep links, the bare add-on address and a proxy path prefix reach the same declared page",
|
|
"esm: a host that does not provide the add-on SDK range never imports its code and says so",
|
|
"esm: a module that imports React by a bare specifier fails to load and no second React is resolved",
|
|
"esm: the server decides asset access: undeclared files, traversal, other add-ons, credentials in URLs and foreign sessions are denied",
|
|
"esm: an add-on navigates only to its own declared pages and the host draws the add-on navigation",
|
|
"esm: dialogs an add-on opens are owned by the host: focus, Escape and the close button",
|
|
"esm: a dialog or panel whose render throws is contained and the host app keeps running",
|
|
"esm: unsaved edits are guarded when leaving the page",
|
|
"esm: the page keeps inside the viewport at 400 px and follows the light and dark themes",
|
|
"esm: a member without the add-ons feature gets no add-on page and no code",
|
|
"esm: disabling an add-on unmounts it, aborts its signal, drops its styles and denies its code at once",
|
|
"esm: a withdrawn add-on with unsaved edits stays on screen until the user decides, and never saves",
|
|
"esm: an update withdraws the old generation, denies its code and loads the new one only on an explicit reload"
|
|
]
|
|
},
|
|
"host-slots": {
|
|
"kind": "shell",
|
|
"commands": [
|
|
[
|
|
"sh",
|
|
"scripts/addons/host_slots.sh"
|
|
]
|
|
],
|
|
"cases": [
|
|
"unit: slots: the registry is closed and each slot has a frozen minimal props contract",
|
|
"unit: slots: props carry only the contract and never message text or history",
|
|
"unit: slots: declared component names come from the manifest only and the module cannot add more",
|
|
"unit: slots: the loader hands the host only declared components and never an imperative registration",
|
|
"unit: slots: contributions come only from enabled, usable, current-generation add-ons that are ready",
|
|
"unit: slots: an action appears only in its declared placement and carries its own target",
|
|
"unit: slots: labels follow the language with a safe fallback",
|
|
"unit: slots: a renderer is found only for the addon own declared tool and kind",
|
|
"unit: slots: an action sends its declared tool and the sanitized context, and results are bounded text",
|
|
"unit: slots: disable, crash and update unmount every contribution through the runtime",
|
|
"unit: slots: contributions keep the apps list polled while they exist",
|
|
"unit: slots: the approval frame decides from the stored proposal and never from the renderer",
|
|
"unit: slots: the SDK can present an approval of its own addon only through the host",
|
|
"unit: slots: a page that only needs the list reads it once and never retries a failed read",
|
|
"go: accepts tool and component chat actions, slots and own-tool renderers",
|
|
"go: keeps bare chat action identifiers and every earlier fixture valid",
|
|
"go: rejects every undeclared, unsafe or inconsistent contribution at install",
|
|
"go: keeps the closed slot list and the icon allowlist equal to the host",
|
|
"go: lists actions, slots and renderers for an enabled addon and keeps the identifiers",
|
|
"go: lists no contribution for a disabled addon, whoever asks",
|
|
"slots: the composer overflow menu holds the declared composer actions and components only",
|
|
"slots: a tool action calls only its declared own tool and draws the declared result renderer",
|
|
"slots: message actions sit in the message action row and carry no message text",
|
|
"slots: a component action opens the add-on component in a host dialog and a throwing one is contained",
|
|
"slots: the host approval frame owns Confirm and Cancel and the card only draws details",
|
|
"slots: the settings page ends with a host-owned section for each contributing add-on",
|
|
"slots: the navigation slot adds its entry after the add-on navigation links of the Build hub",
|
|
"slots: add-on style sheets that collide with host class names change no host node",
|
|
"slots: keyboard users open the menu, move through it, close it with Escape and run an action",
|
|
"slots: the layout keeps inside a 400 px screen in the light theme",
|
|
"slots: a caller without the add-ons feature sees no contribution and the server denies the tool call",
|
|
"slots: disabling the add-on through the real owner removes every contribution and enabling brings them back"
|
|
]
|
|
},
|
|
"foundation-acceptance": {
|
|
"kind": "shell",
|
|
"commands": [
|
|
[
|
|
"sh",
|
|
"scripts/addons/foundation.sh"
|
|
]
|
|
],
|
|
"cases": [
|
|
"go: fails closed on every frontend while the owner is down, executes nothing locally and recovers the last good package and data on restart",
|
|
"go: refuses a second owner on the same storage and keeps one process per add-on",
|
|
"go: stops an add-on process orphaned by an owner crash before it starts the next one",
|
|
"go: leaves no process behind when a cluster with an orphaned add-on is taken down",
|
|
"go: keeps the last good generation running and its data when an upgrade fails to start",
|
|
"go: keeps the last good code and data when the owner is killed in the middle of an upgrade and recovers on restart",
|
|
"go: keeps retained data and a consistent lifecycle when the owner is killed in the middle of an enable",
|
|
"go: keeps the files of the package of an installed add-on read only",
|
|
"go: keeps the last good generation running and the retained data when the new generation cannot start",
|
|
"go: restores the last good generation and resumes the same operation when the request is canceled during an upgrade start",
|
|
"go: converges on the last good generation after a crash that follows the rollback start and precedes any journal write",
|
|
"go: starts the owner when an enabled add-on cannot become ready and fails only that add-on",
|
|
"go: gives an ordinary account the apps list and no management on any node",
|
|
"go: returns the same typed denial from the owner and from each frontend",
|
|
"go: refuses a session on every node once it was ended through one frontend",
|
|
"go: refuses an API key on every node once it was revoked through one frontend",
|
|
"go: installs the UI, tool and service-only packages from the catalog through a frontend without starting them and leaves the host binary and UI build unchanged",
|
|
"go: activates each package through the other frontend and runs one process per add-on under the owner only",
|
|
"go: lists the same apps from the owner and both frontends and shows only what each declared",
|
|
"go: serves reads of the UI, tool and service-only packages alternately through the owner and both frontends",
|
|
"go: denies an account without the feature, a stranger to the resource and an anonymous caller the same way on every node",
|
|
"go: takes the actor from the authenticated credential only and ignores forged actor and authority headers",
|
|
"go: denies a tool the add-on did not declare and a generation that is not current on every node",
|
|
"go: relays JSON and a private file result and downloads the file through a different frontend than the one that produced it",
|
|
"go: relays lifecycle status and progress of an operation to the administrator who made it and to nobody else",
|
|
"go: serves the immutable UI assets by package digest through a non-owner frontend and refuses everything else",
|
|
"go: applies one confirmed change exactly once through a different frontend than the one that proposed it",
|
|
"go: reports a lost reply as outcome unknown with the original operation ID and settles it by receipt lookup without a second apply",
|
|
"go: upgrades to a new generation, denies the previous generation and its assets, and keeps the retained data",
|
|
"go: disables, removes and reinstalls an add-on while its data and grants remain",
|
|
"go: never changes the host binary or the shipped UI build over the whole lifecycle",
|
|
"regression: model and backend gallery specs (core/gallery)",
|
|
"regression: gallery operation specs (core/services/galleryop)",
|
|
"regression: process adapter specs (pkg/model)",
|
|
"foundation: a member opens the add-on through each non-owner frontend and its module comes from the owner by digest",
|
|
"foundation: the owner and both frontends list the same add-on to the same account",
|
|
"foundation: a member sees the Apps list only and the server refuses every management request",
|
|
"foundation: an account without the add-ons feature gets no apps and no code on any node",
|
|
"foundation: an administrator manages through a frontend and the change is the owner's",
|
|
"foundation: deep links of the add-on page work behind a proxy path prefix on a non-owner frontend",
|
|
"foundation: a session ended through one frontend is refused for add-on assets by the other servers"
|
|
]
|
|
},
|
|
"tables-databases": {
|
|
"kind": "ginkgo",
|
|
"commands": [
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./addons/tables/internal/store",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/tables-databases-store.json"
|
|
],
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./tests/addons/tables",
|
|
"-ginkgo.json-report=../../../.cache/addons/logs/tables-databases.json"
|
|
]
|
|
],
|
|
"report": ".cache/addons/logs/tables-databases-store.json",
|
|
"reports": [
|
|
{
|
|
"path": ".cache/addons/logs/tables-databases-store.json",
|
|
"cases": [
|
|
"enforces the size cap on every connection and fails with a typed capacity error",
|
|
"builds a database under a data directory containing percent, question and hash characters",
|
|
"leaves no change and no receipt when the process dies before commit, and the ID can still apply",
|
|
"finds the committed receipt after a crash between commit and reply and never applies twice",
|
|
"replays one operation ID to one receipt and refuses another request under the same ID",
|
|
"applies one change once when the same operation arrives concurrently",
|
|
"keeps a rejected change out of the receipts so its ID is not burnt",
|
|
"encodes the receipt payload so the host can read what changed",
|
|
"creates, renames and drops tables with stable internal identifiers and one revision step each",
|
|
"adds typed columns, renames them without touching identifiers and never uses a label in SQL",
|
|
"validates labels by length, characters and case-insensitive uniqueness",
|
|
"refuses type changes, unknown operations, expressions and unknown types",
|
|
"encodes typed defaults as literals and survives hostile defaults",
|
|
"enforces required columns and refuses unique defaults that would collide",
|
|
"adds a unique column through a unique index and refuses duplicates atomically",
|
|
"drops a column by rebuilding the table and loses exactly what the preview reported",
|
|
"never hands out a row ID again after a column drop rebuilds the table",
|
|
"keeps the row ID counter when a column drop rebuilds a table emptied by deletes",
|
|
"leaves the original table, data and revision intact when a rebuild fails midway",
|
|
"previews exact effects and dependent data loss and changes nothing",
|
|
"refuses a stale expected revision with the current revision and applies nothing",
|
|
"keeps finite limits on tables and columns",
|
|
"migrates a database made before the catalog existed on its first schema change",
|
|
"inserts bound rows atomically with defaults, required and unique checks",
|
|
"updates by explicit IDs and by filter and bumps only the data revision",
|
|
"deletes by IDs or filter and refuses broad, empty or oversized selections",
|
|
"previews exact count, sample and conflicts without changing anything",
|
|
"refuses a changed revision and never re-evaluates a filter against new rows",
|
|
"applies exactly one of two proposals made on the same revision",
|
|
"replays a row operation by ID and refuses another request under the same ID",
|
|
"leaves no change when the process dies before commit and finds the receipt after commit",
|
|
"reserves the row id label so no column can shadow it",
|
|
"keeps a row table's data across a column drop that rebuilds it",
|
|
"reads selected columns with stable row IDs and typed JSON values",
|
|
"filters with bounded AND/OR trees and every operator, matching a reference evaluator on random trees",
|
|
"escapes LIKE wildcards in text filters",
|
|
"keeps NULL semantics: comparisons never match NULL and is-null finds it",
|
|
"sorts with a stable row ID tie-break and pages through a cursor that stops at a revision change",
|
|
"counts, sums, averages and bounds groups of aggregates",
|
|
"reports a real sum or average that overflows as the typed arithmetic error",
|
|
"never lets a label, operator or value reach SQL as text",
|
|
"honours hard limits on page size, filter depth, conditions, in-lists, sort keys and result bytes",
|
|
"stops a query when the context is cancelled or the deadline passes",
|
|
"encodes all five types as JSON and writes 64-bit integers as strings beyond 2^53",
|
|
"orders datetimes chronologically across fractional seconds and offsets",
|
|
"creates one private WAL database file named by the host resource ID",
|
|
"never lets an opaque ID or a name reach outside the storage directory",
|
|
"refuses a symbolic link as storage directory, database file or ledger",
|
|
"is idempotent by operation ID and never creates a second database",
|
|
"serializes concurrent creation of one operation into one database",
|
|
"recovers creation after a crash on either side of the file, and hides half-built files",
|
|
"renames only the named database and replays a renamed operation without effect",
|
|
"reports an unknown database and creates nothing for it",
|
|
"honours the busy timeout and the per-operation deadline, then succeeds once the lock is gone",
|
|
"encodes its receipts so the host can read them",
|
|
"writes a header and one record per row with RFC 4180 quoting, UTF-8 and the documented value forms",
|
|
"prefixes text cells and labels that a spreadsheet would run, never numbers",
|
|
"honours columns, the row identifier column, filter, sort and the row limit of the query",
|
|
"reads one snapshot: writes that commit while the export streams are not in it, and are not blocked by it",
|
|
"streams a large table row by row with bounded memory",
|
|
"fails cleanly past the row or byte bound and keeps the bound finite by default",
|
|
"stops on cancellation, on its deadline and on a failing destination, and reports each",
|
|
"does not change the database it reads",
|
|
"records the current format of a new store and migrates nothing",
|
|
"migrates every database in its own transaction, records the version last and repeats as a no-op",
|
|
"leaves a database whose step fails exactly as it was and resumes on the next run",
|
|
"refuses data in a newer format, a downgrade and a version it has no path to, and writes nothing",
|
|
"leaves no pending line for a change the add-on refused, so the same ID applies the corrected request"
|
|
]
|
|
},
|
|
{
|
|
"path": ".cache/addons/logs/tables-databases.json",
|
|
"cases": [
|
|
"starts the real executable through the authenticated handshake and refuses unauthenticated callers",
|
|
"creates a database under the host-assigned ID and lists it only for people who may read it",
|
|
"drops the reservation when the addon refuses the name, and leaves no database",
|
|
"drops a reservation at reconcile when the crash came before the database was created",
|
|
"commits a reservation at reconcile when the crash came after the database was created",
|
|
"never exposes a database that has no host record",
|
|
"renames one database by operation, replays safely, and leaves every other database alone",
|
|
"rejects an undeclared tool, a forged addon binding and an unknown resource",
|
|
"keeps databases and operation receipts across an addon restart",
|
|
"fails closed when the addon cannot answer, and drops only for an addon that is not installed",
|
|
"creates a database from a chat proposal that only the proposer's session confirms",
|
|
"settles reservations at bootstrap by asking the real addon and keeps those of pending proposals",
|
|
"reads and mutates rows with the exact preview, refuses wrong actions and keeps receipts across a restart",
|
|
"declares the row tools and refuses a row tool the manifest does not name",
|
|
"changes the schema as the owner, shows data loss in the preview and refuses an editor at the host and the addon",
|
|
"rejects a stale schema revision, replays an operation and keeps receipts across a restart",
|
|
"declares the schema tools and refuses any schema tool the manifest does not name",
|
|
"applies row changes only on the proposer's confirmation and rejects a proposal whose database moved",
|
|
"offers the manifest tools to a permitted user and nothing to a user without the feature or after revocation",
|
|
"stores every change as a pending proposal and applies it only on the proposer's own session, exactly once",
|
|
"keeps the roles of the host for tool calls and rejects forged fields before the owner sees them",
|
|
"lists at most the bound of pending proposals and refuses more than the user's quota"
|
|
]
|
|
}
|
|
],
|
|
"cases": [
|
|
"enforces the size cap on every connection and fails with a typed capacity error",
|
|
"builds a database under a data directory containing percent, question and hash characters",
|
|
"leaves no change and no receipt when the process dies before commit, and the ID can still apply",
|
|
"finds the committed receipt after a crash between commit and reply and never applies twice",
|
|
"replays one operation ID to one receipt and refuses another request under the same ID",
|
|
"applies one change once when the same operation arrives concurrently",
|
|
"keeps a rejected change out of the receipts so its ID is not burnt",
|
|
"encodes the receipt payload so the host can read what changed",
|
|
"creates, renames and drops tables with stable internal identifiers and one revision step each",
|
|
"adds typed columns, renames them without touching identifiers and never uses a label in SQL",
|
|
"validates labels by length, characters and case-insensitive uniqueness",
|
|
"refuses type changes, unknown operations, expressions and unknown types",
|
|
"encodes typed defaults as literals and survives hostile defaults",
|
|
"enforces required columns and refuses unique defaults that would collide",
|
|
"adds a unique column through a unique index and refuses duplicates atomically",
|
|
"drops a column by rebuilding the table and loses exactly what the preview reported",
|
|
"never hands out a row ID again after a column drop rebuilds the table",
|
|
"keeps the row ID counter when a column drop rebuilds a table emptied by deletes",
|
|
"leaves the original table, data and revision intact when a rebuild fails midway",
|
|
"previews exact effects and dependent data loss and changes nothing",
|
|
"refuses a stale expected revision with the current revision and applies nothing",
|
|
"keeps finite limits on tables and columns",
|
|
"migrates a database made before the catalog existed on its first schema change",
|
|
"inserts bound rows atomically with defaults, required and unique checks",
|
|
"updates by explicit IDs and by filter and bumps only the data revision",
|
|
"deletes by IDs or filter and refuses broad, empty or oversized selections",
|
|
"previews exact count, sample and conflicts without changing anything",
|
|
"refuses a changed revision and never re-evaluates a filter against new rows",
|
|
"applies exactly one of two proposals made on the same revision",
|
|
"replays a row operation by ID and refuses another request under the same ID",
|
|
"leaves no change when the process dies before commit and finds the receipt after commit",
|
|
"reserves the row id label so no column can shadow it",
|
|
"keeps a row table's data across a column drop that rebuilds it",
|
|
"reads selected columns with stable row IDs and typed JSON values",
|
|
"filters with bounded AND/OR trees and every operator, matching a reference evaluator on random trees",
|
|
"escapes LIKE wildcards in text filters",
|
|
"keeps NULL semantics: comparisons never match NULL and is-null finds it",
|
|
"sorts with a stable row ID tie-break and pages through a cursor that stops at a revision change",
|
|
"counts, sums, averages and bounds groups of aggregates",
|
|
"reports a real sum or average that overflows as the typed arithmetic error",
|
|
"never lets a label, operator or value reach SQL as text",
|
|
"honours hard limits on page size, filter depth, conditions, in-lists, sort keys and result bytes",
|
|
"stops a query when the context is cancelled or the deadline passes",
|
|
"encodes all five types as JSON and writes 64-bit integers as strings beyond 2^53",
|
|
"orders datetimes chronologically across fractional seconds and offsets",
|
|
"creates one private WAL database file named by the host resource ID",
|
|
"never lets an opaque ID or a name reach outside the storage directory",
|
|
"refuses a symbolic link as storage directory, database file or ledger",
|
|
"is idempotent by operation ID and never creates a second database",
|
|
"serializes concurrent creation of one operation into one database",
|
|
"recovers creation after a crash on either side of the file, and hides half-built files",
|
|
"renames only the named database and replays a renamed operation without effect",
|
|
"reports an unknown database and creates nothing for it",
|
|
"honours the busy timeout and the per-operation deadline, then succeeds once the lock is gone",
|
|
"encodes its receipts so the host can read them",
|
|
"writes a header and one record per row with RFC 4180 quoting, UTF-8 and the documented value forms",
|
|
"prefixes text cells and labels that a spreadsheet would run, never numbers",
|
|
"honours columns, the row identifier column, filter, sort and the row limit of the query",
|
|
"reads one snapshot: writes that commit while the export streams are not in it, and are not blocked by it",
|
|
"streams a large table row by row with bounded memory",
|
|
"fails cleanly past the row or byte bound and keeps the bound finite by default",
|
|
"stops on cancellation, on its deadline and on a failing destination, and reports each",
|
|
"does not change the database it reads",
|
|
"records the current format of a new store and migrates nothing",
|
|
"migrates every database in its own transaction, records the version last and repeats as a no-op",
|
|
"leaves a database whose step fails exactly as it was and resumes on the next run",
|
|
"refuses data in a newer format, a downgrade and a version it has no path to, and writes nothing",
|
|
"leaves no pending line for a change the add-on refused, so the same ID applies the corrected request",
|
|
"starts the real executable through the authenticated handshake and refuses unauthenticated callers",
|
|
"creates a database under the host-assigned ID and lists it only for people who may read it",
|
|
"drops the reservation when the addon refuses the name, and leaves no database",
|
|
"drops a reservation at reconcile when the crash came before the database was created",
|
|
"commits a reservation at reconcile when the crash came after the database was created",
|
|
"never exposes a database that has no host record",
|
|
"renames one database by operation, replays safely, and leaves every other database alone",
|
|
"rejects an undeclared tool, a forged addon binding and an unknown resource",
|
|
"keeps databases and operation receipts across an addon restart",
|
|
"fails closed when the addon cannot answer, and drops only for an addon that is not installed",
|
|
"creates a database from a chat proposal that only the proposer's session confirms",
|
|
"settles reservations at bootstrap by asking the real addon and keeps those of pending proposals",
|
|
"reads and mutates rows with the exact preview, refuses wrong actions and keeps receipts across a restart",
|
|
"declares the row tools and refuses a row tool the manifest does not name",
|
|
"changes the schema as the owner, shows data loss in the preview and refuses an editor at the host and the addon",
|
|
"rejects a stale schema revision, replays an operation and keeps receipts across a restart",
|
|
"declares the schema tools and refuses any schema tool the manifest does not name",
|
|
"applies row changes only on the proposer's confirmation and rejects a proposal whose database moved",
|
|
"offers the manifest tools to a permitted user and nothing to a user without the feature or after revocation",
|
|
"stores every change as a pending proposal and applies it only on the proposer's own session, exactly once",
|
|
"keeps the roles of the host for tool calls and rejects forged fields before the owner sees them",
|
|
"lists at most the bound of pending proposals and refuses more than the user's quota"
|
|
]
|
|
},
|
|
"tables-schema": {
|
|
"kind": "ginkgo",
|
|
"commands": [
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./addons/tables/internal/store",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/tables-schema-store.json"
|
|
],
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./tests/addons/tables",
|
|
"-ginkgo.json-report=../../../.cache/addons/logs/tables-schema.json"
|
|
]
|
|
],
|
|
"report": ".cache/addons/logs/tables-schema-store.json",
|
|
"reports": [
|
|
{
|
|
"path": ".cache/addons/logs/tables-schema-store.json",
|
|
"cases": [
|
|
"enforces the size cap on every connection and fails with a typed capacity error",
|
|
"builds a database under a data directory containing percent, question and hash characters",
|
|
"leaves no change and no receipt when the process dies before commit, and the ID can still apply",
|
|
"finds the committed receipt after a crash between commit and reply and never applies twice",
|
|
"replays one operation ID to one receipt and refuses another request under the same ID",
|
|
"applies one change once when the same operation arrives concurrently",
|
|
"keeps a rejected change out of the receipts so its ID is not burnt",
|
|
"encodes the receipt payload so the host can read what changed",
|
|
"creates, renames and drops tables with stable internal identifiers and one revision step each",
|
|
"adds typed columns, renames them without touching identifiers and never uses a label in SQL",
|
|
"validates labels by length, characters and case-insensitive uniqueness",
|
|
"refuses type changes, unknown operations, expressions and unknown types",
|
|
"encodes typed defaults as literals and survives hostile defaults",
|
|
"enforces required columns and refuses unique defaults that would collide",
|
|
"adds a unique column through a unique index and refuses duplicates atomically",
|
|
"drops a column by rebuilding the table and loses exactly what the preview reported",
|
|
"never hands out a row ID again after a column drop rebuilds the table",
|
|
"keeps the row ID counter when a column drop rebuilds a table emptied by deletes",
|
|
"leaves the original table, data and revision intact when a rebuild fails midway",
|
|
"previews exact effects and dependent data loss and changes nothing",
|
|
"refuses a stale expected revision with the current revision and applies nothing",
|
|
"keeps finite limits on tables and columns",
|
|
"migrates a database made before the catalog existed on its first schema change",
|
|
"inserts bound rows atomically with defaults, required and unique checks",
|
|
"updates by explicit IDs and by filter and bumps only the data revision",
|
|
"deletes by IDs or filter and refuses broad, empty or oversized selections",
|
|
"previews exact count, sample and conflicts without changing anything",
|
|
"refuses a changed revision and never re-evaluates a filter against new rows",
|
|
"applies exactly one of two proposals made on the same revision",
|
|
"replays a row operation by ID and refuses another request under the same ID",
|
|
"leaves no change when the process dies before commit and finds the receipt after commit",
|
|
"reserves the row id label so no column can shadow it",
|
|
"keeps a row table's data across a column drop that rebuilds it",
|
|
"reads selected columns with stable row IDs and typed JSON values",
|
|
"filters with bounded AND/OR trees and every operator, matching a reference evaluator on random trees",
|
|
"escapes LIKE wildcards in text filters",
|
|
"keeps NULL semantics: comparisons never match NULL and is-null finds it",
|
|
"sorts with a stable row ID tie-break and pages through a cursor that stops at a revision change",
|
|
"counts, sums, averages and bounds groups of aggregates",
|
|
"reports a real sum or average that overflows as the typed arithmetic error",
|
|
"never lets a label, operator or value reach SQL as text",
|
|
"honours hard limits on page size, filter depth, conditions, in-lists, sort keys and result bytes",
|
|
"stops a query when the context is cancelled or the deadline passes",
|
|
"encodes all five types as JSON and writes 64-bit integers as strings beyond 2^53",
|
|
"orders datetimes chronologically across fractional seconds and offsets",
|
|
"creates one private WAL database file named by the host resource ID",
|
|
"never lets an opaque ID or a name reach outside the storage directory",
|
|
"refuses a symbolic link as storage directory, database file or ledger",
|
|
"is idempotent by operation ID and never creates a second database",
|
|
"serializes concurrent creation of one operation into one database",
|
|
"recovers creation after a crash on either side of the file, and hides half-built files",
|
|
"renames only the named database and replays a renamed operation without effect",
|
|
"reports an unknown database and creates nothing for it",
|
|
"honours the busy timeout and the per-operation deadline, then succeeds once the lock is gone",
|
|
"encodes its receipts so the host can read them",
|
|
"writes a header and one record per row with RFC 4180 quoting, UTF-8 and the documented value forms",
|
|
"prefixes text cells and labels that a spreadsheet would run, never numbers",
|
|
"honours columns, the row identifier column, filter, sort and the row limit of the query",
|
|
"reads one snapshot: writes that commit while the export streams are not in it, and are not blocked by it",
|
|
"streams a large table row by row with bounded memory",
|
|
"fails cleanly past the row or byte bound and keeps the bound finite by default",
|
|
"stops on cancellation, on its deadline and on a failing destination, and reports each",
|
|
"does not change the database it reads",
|
|
"records the current format of a new store and migrates nothing",
|
|
"migrates every database in its own transaction, records the version last and repeats as a no-op",
|
|
"leaves a database whose step fails exactly as it was and resumes on the next run",
|
|
"refuses data in a newer format, a downgrade and a version it has no path to, and writes nothing",
|
|
"leaves no pending line for a change the add-on refused, so the same ID applies the corrected request"
|
|
]
|
|
},
|
|
{
|
|
"path": ".cache/addons/logs/tables-schema.json",
|
|
"cases": [
|
|
"starts the real executable through the authenticated handshake and refuses unauthenticated callers",
|
|
"creates a database under the host-assigned ID and lists it only for people who may read it",
|
|
"drops the reservation when the addon refuses the name, and leaves no database",
|
|
"drops a reservation at reconcile when the crash came before the database was created",
|
|
"commits a reservation at reconcile when the crash came after the database was created",
|
|
"never exposes a database that has no host record",
|
|
"renames one database by operation, replays safely, and leaves every other database alone",
|
|
"rejects an undeclared tool, a forged addon binding and an unknown resource",
|
|
"keeps databases and operation receipts across an addon restart",
|
|
"fails closed when the addon cannot answer, and drops only for an addon that is not installed",
|
|
"creates a database from a chat proposal that only the proposer's session confirms",
|
|
"settles reservations at bootstrap by asking the real addon and keeps those of pending proposals",
|
|
"reads and mutates rows with the exact preview, refuses wrong actions and keeps receipts across a restart",
|
|
"declares the row tools and refuses a row tool the manifest does not name",
|
|
"changes the schema as the owner, shows data loss in the preview and refuses an editor at the host and the addon",
|
|
"rejects a stale schema revision, replays an operation and keeps receipts across a restart",
|
|
"declares the schema tools and refuses any schema tool the manifest does not name",
|
|
"applies row changes only on the proposer's confirmation and rejects a proposal whose database moved",
|
|
"offers the manifest tools to a permitted user and nothing to a user without the feature or after revocation",
|
|
"stores every change as a pending proposal and applies it only on the proposer's own session, exactly once",
|
|
"keeps the roles of the host for tool calls and rejects forged fields before the owner sees them",
|
|
"lists at most the bound of pending proposals and refuses more than the user's quota"
|
|
]
|
|
}
|
|
],
|
|
"cases": [
|
|
"enforces the size cap on every connection and fails with a typed capacity error",
|
|
"builds a database under a data directory containing percent, question and hash characters",
|
|
"leaves no change and no receipt when the process dies before commit, and the ID can still apply",
|
|
"finds the committed receipt after a crash between commit and reply and never applies twice",
|
|
"replays one operation ID to one receipt and refuses another request under the same ID",
|
|
"applies one change once when the same operation arrives concurrently",
|
|
"keeps a rejected change out of the receipts so its ID is not burnt",
|
|
"encodes the receipt payload so the host can read what changed",
|
|
"creates, renames and drops tables with stable internal identifiers and one revision step each",
|
|
"adds typed columns, renames them without touching identifiers and never uses a label in SQL",
|
|
"validates labels by length, characters and case-insensitive uniqueness",
|
|
"refuses type changes, unknown operations, expressions and unknown types",
|
|
"encodes typed defaults as literals and survives hostile defaults",
|
|
"enforces required columns and refuses unique defaults that would collide",
|
|
"adds a unique column through a unique index and refuses duplicates atomically",
|
|
"drops a column by rebuilding the table and loses exactly what the preview reported",
|
|
"never hands out a row ID again after a column drop rebuilds the table",
|
|
"keeps the row ID counter when a column drop rebuilds a table emptied by deletes",
|
|
"leaves the original table, data and revision intact when a rebuild fails midway",
|
|
"previews exact effects and dependent data loss and changes nothing",
|
|
"refuses a stale expected revision with the current revision and applies nothing",
|
|
"keeps finite limits on tables and columns",
|
|
"migrates a database made before the catalog existed on its first schema change",
|
|
"inserts bound rows atomically with defaults, required and unique checks",
|
|
"updates by explicit IDs and by filter and bumps only the data revision",
|
|
"deletes by IDs or filter and refuses broad, empty or oversized selections",
|
|
"previews exact count, sample and conflicts without changing anything",
|
|
"refuses a changed revision and never re-evaluates a filter against new rows",
|
|
"applies exactly one of two proposals made on the same revision",
|
|
"replays a row operation by ID and refuses another request under the same ID",
|
|
"leaves no change when the process dies before commit and finds the receipt after commit",
|
|
"reserves the row id label so no column can shadow it",
|
|
"keeps a row table's data across a column drop that rebuilds it",
|
|
"reads selected columns with stable row IDs and typed JSON values",
|
|
"filters with bounded AND/OR trees and every operator, matching a reference evaluator on random trees",
|
|
"escapes LIKE wildcards in text filters",
|
|
"keeps NULL semantics: comparisons never match NULL and is-null finds it",
|
|
"sorts with a stable row ID tie-break and pages through a cursor that stops at a revision change",
|
|
"counts, sums, averages and bounds groups of aggregates",
|
|
"reports a real sum or average that overflows as the typed arithmetic error",
|
|
"never lets a label, operator or value reach SQL as text",
|
|
"honours hard limits on page size, filter depth, conditions, in-lists, sort keys and result bytes",
|
|
"stops a query when the context is cancelled or the deadline passes",
|
|
"encodes all five types as JSON and writes 64-bit integers as strings beyond 2^53",
|
|
"orders datetimes chronologically across fractional seconds and offsets",
|
|
"creates one private WAL database file named by the host resource ID",
|
|
"never lets an opaque ID or a name reach outside the storage directory",
|
|
"refuses a symbolic link as storage directory, database file or ledger",
|
|
"is idempotent by operation ID and never creates a second database",
|
|
"serializes concurrent creation of one operation into one database",
|
|
"recovers creation after a crash on either side of the file, and hides half-built files",
|
|
"renames only the named database and replays a renamed operation without effect",
|
|
"reports an unknown database and creates nothing for it",
|
|
"honours the busy timeout and the per-operation deadline, then succeeds once the lock is gone",
|
|
"encodes its receipts so the host can read them",
|
|
"writes a header and one record per row with RFC 4180 quoting, UTF-8 and the documented value forms",
|
|
"prefixes text cells and labels that a spreadsheet would run, never numbers",
|
|
"honours columns, the row identifier column, filter, sort and the row limit of the query",
|
|
"reads one snapshot: writes that commit while the export streams are not in it, and are not blocked by it",
|
|
"streams a large table row by row with bounded memory",
|
|
"fails cleanly past the row or byte bound and keeps the bound finite by default",
|
|
"stops on cancellation, on its deadline and on a failing destination, and reports each",
|
|
"does not change the database it reads",
|
|
"records the current format of a new store and migrates nothing",
|
|
"migrates every database in its own transaction, records the version last and repeats as a no-op",
|
|
"leaves a database whose step fails exactly as it was and resumes on the next run",
|
|
"refuses data in a newer format, a downgrade and a version it has no path to, and writes nothing",
|
|
"leaves no pending line for a change the add-on refused, so the same ID applies the corrected request",
|
|
"starts the real executable through the authenticated handshake and refuses unauthenticated callers",
|
|
"creates a database under the host-assigned ID and lists it only for people who may read it",
|
|
"drops the reservation when the addon refuses the name, and leaves no database",
|
|
"drops a reservation at reconcile when the crash came before the database was created",
|
|
"commits a reservation at reconcile when the crash came after the database was created",
|
|
"never exposes a database that has no host record",
|
|
"renames one database by operation, replays safely, and leaves every other database alone",
|
|
"rejects an undeclared tool, a forged addon binding and an unknown resource",
|
|
"keeps databases and operation receipts across an addon restart",
|
|
"fails closed when the addon cannot answer, and drops only for an addon that is not installed",
|
|
"creates a database from a chat proposal that only the proposer's session confirms",
|
|
"settles reservations at bootstrap by asking the real addon and keeps those of pending proposals",
|
|
"reads and mutates rows with the exact preview, refuses wrong actions and keeps receipts across a restart",
|
|
"declares the row tools and refuses a row tool the manifest does not name",
|
|
"changes the schema as the owner, shows data loss in the preview and refuses an editor at the host and the addon",
|
|
"rejects a stale schema revision, replays an operation and keeps receipts across a restart",
|
|
"declares the schema tools and refuses any schema tool the manifest does not name",
|
|
"applies row changes only on the proposer's confirmation and rejects a proposal whose database moved",
|
|
"offers the manifest tools to a permitted user and nothing to a user without the feature or after revocation",
|
|
"stores every change as a pending proposal and applies it only on the proposer's own session, exactly once",
|
|
"keeps the roles of the host for tool calls and rejects forged fields before the owner sees them",
|
|
"lists at most the bound of pending proposals and refuses more than the user's quota"
|
|
]
|
|
},
|
|
"tables-rows": {
|
|
"kind": "ginkgo",
|
|
"commands": [
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./addons/tables/internal/store",
|
|
"-ginkgo.json-report=../../../../.cache/addons/logs/tables-rows-store.json"
|
|
],
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./tests/addons/tables",
|
|
"-ginkgo.json-report=../../../.cache/addons/logs/tables-rows.json"
|
|
]
|
|
],
|
|
"report": ".cache/addons/logs/tables-rows-store.json",
|
|
"reports": [
|
|
{
|
|
"path": ".cache/addons/logs/tables-rows-store.json",
|
|
"cases": [
|
|
"enforces the size cap on every connection and fails with a typed capacity error",
|
|
"builds a database under a data directory containing percent, question and hash characters",
|
|
"leaves no change and no receipt when the process dies before commit, and the ID can still apply",
|
|
"finds the committed receipt after a crash between commit and reply and never applies twice",
|
|
"replays one operation ID to one receipt and refuses another request under the same ID",
|
|
"applies one change once when the same operation arrives concurrently",
|
|
"keeps a rejected change out of the receipts so its ID is not burnt",
|
|
"encodes the receipt payload so the host can read what changed",
|
|
"creates, renames and drops tables with stable internal identifiers and one revision step each",
|
|
"adds typed columns, renames them without touching identifiers and never uses a label in SQL",
|
|
"validates labels by length, characters and case-insensitive uniqueness",
|
|
"refuses type changes, unknown operations, expressions and unknown types",
|
|
"encodes typed defaults as literals and survives hostile defaults",
|
|
"enforces required columns and refuses unique defaults that would collide",
|
|
"adds a unique column through a unique index and refuses duplicates atomically",
|
|
"drops a column by rebuilding the table and loses exactly what the preview reported",
|
|
"never hands out a row ID again after a column drop rebuilds the table",
|
|
"keeps the row ID counter when a column drop rebuilds a table emptied by deletes",
|
|
"leaves the original table, data and revision intact when a rebuild fails midway",
|
|
"previews exact effects and dependent data loss and changes nothing",
|
|
"refuses a stale expected revision with the current revision and applies nothing",
|
|
"keeps finite limits on tables and columns",
|
|
"migrates a database made before the catalog existed on its first schema change",
|
|
"inserts bound rows atomically with defaults, required and unique checks",
|
|
"updates by explicit IDs and by filter and bumps only the data revision",
|
|
"deletes by IDs or filter and refuses broad, empty or oversized selections",
|
|
"previews exact count, sample and conflicts without changing anything",
|
|
"refuses a changed revision and never re-evaluates a filter against new rows",
|
|
"applies exactly one of two proposals made on the same revision",
|
|
"replays a row operation by ID and refuses another request under the same ID",
|
|
"leaves no change when the process dies before commit and finds the receipt after commit",
|
|
"reserves the row id label so no column can shadow it",
|
|
"keeps a row table's data across a column drop that rebuilds it",
|
|
"reads selected columns with stable row IDs and typed JSON values",
|
|
"filters with bounded AND/OR trees and every operator, matching a reference evaluator on random trees",
|
|
"escapes LIKE wildcards in text filters",
|
|
"keeps NULL semantics: comparisons never match NULL and is-null finds it",
|
|
"sorts with a stable row ID tie-break and pages through a cursor that stops at a revision change",
|
|
"counts, sums, averages and bounds groups of aggregates",
|
|
"reports a real sum or average that overflows as the typed arithmetic error",
|
|
"never lets a label, operator or value reach SQL as text",
|
|
"honours hard limits on page size, filter depth, conditions, in-lists, sort keys and result bytes",
|
|
"stops a query when the context is cancelled or the deadline passes",
|
|
"encodes all five types as JSON and writes 64-bit integers as strings beyond 2^53",
|
|
"orders datetimes chronologically across fractional seconds and offsets",
|
|
"creates one private WAL database file named by the host resource ID",
|
|
"never lets an opaque ID or a name reach outside the storage directory",
|
|
"refuses a symbolic link as storage directory, database file or ledger",
|
|
"is idempotent by operation ID and never creates a second database",
|
|
"serializes concurrent creation of one operation into one database",
|
|
"recovers creation after a crash on either side of the file, and hides half-built files",
|
|
"renames only the named database and replays a renamed operation without effect",
|
|
"reports an unknown database and creates nothing for it",
|
|
"honours the busy timeout and the per-operation deadline, then succeeds once the lock is gone",
|
|
"encodes its receipts so the host can read them",
|
|
"writes a header and one record per row with RFC 4180 quoting, UTF-8 and the documented value forms",
|
|
"prefixes text cells and labels that a spreadsheet would run, never numbers",
|
|
"honours columns, the row identifier column, filter, sort and the row limit of the query",
|
|
"reads one snapshot: writes that commit while the export streams are not in it, and are not blocked by it",
|
|
"streams a large table row by row with bounded memory",
|
|
"fails cleanly past the row or byte bound and keeps the bound finite by default",
|
|
"stops on cancellation, on its deadline and on a failing destination, and reports each",
|
|
"does not change the database it reads",
|
|
"records the current format of a new store and migrates nothing",
|
|
"migrates every database in its own transaction, records the version last and repeats as a no-op",
|
|
"leaves a database whose step fails exactly as it was and resumes on the next run",
|
|
"refuses data in a newer format, a downgrade and a version it has no path to, and writes nothing",
|
|
"leaves no pending line for a change the add-on refused, so the same ID applies the corrected request"
|
|
]
|
|
},
|
|
{
|
|
"path": ".cache/addons/logs/tables-rows.json",
|
|
"cases": [
|
|
"starts the real executable through the authenticated handshake and refuses unauthenticated callers",
|
|
"creates a database under the host-assigned ID and lists it only for people who may read it",
|
|
"drops the reservation when the addon refuses the name, and leaves no database",
|
|
"drops a reservation at reconcile when the crash came before the database was created",
|
|
"commits a reservation at reconcile when the crash came after the database was created",
|
|
"never exposes a database that has no host record",
|
|
"renames one database by operation, replays safely, and leaves every other database alone",
|
|
"rejects an undeclared tool, a forged addon binding and an unknown resource",
|
|
"keeps databases and operation receipts across an addon restart",
|
|
"fails closed when the addon cannot answer, and drops only for an addon that is not installed",
|
|
"creates a database from a chat proposal that only the proposer's session confirms",
|
|
"settles reservations at bootstrap by asking the real addon and keeps those of pending proposals",
|
|
"reads and mutates rows with the exact preview, refuses wrong actions and keeps receipts across a restart",
|
|
"declares the row tools and refuses a row tool the manifest does not name",
|
|
"changes the schema as the owner, shows data loss in the preview and refuses an editor at the host and the addon",
|
|
"rejects a stale schema revision, replays an operation and keeps receipts across a restart",
|
|
"declares the schema tools and refuses any schema tool the manifest does not name",
|
|
"applies row changes only on the proposer's confirmation and rejects a proposal whose database moved",
|
|
"offers the manifest tools to a permitted user and nothing to a user without the feature or after revocation",
|
|
"stores every change as a pending proposal and applies it only on the proposer's own session, exactly once",
|
|
"keeps the roles of the host for tool calls and rejects forged fields before the owner sees them",
|
|
"lists at most the bound of pending proposals and refuses more than the user's quota"
|
|
]
|
|
}
|
|
],
|
|
"cases": [
|
|
"enforces the size cap on every connection and fails with a typed capacity error",
|
|
"builds a database under a data directory containing percent, question and hash characters",
|
|
"leaves no change and no receipt when the process dies before commit, and the ID can still apply",
|
|
"finds the committed receipt after a crash between commit and reply and never applies twice",
|
|
"replays one operation ID to one receipt and refuses another request under the same ID",
|
|
"applies one change once when the same operation arrives concurrently",
|
|
"keeps a rejected change out of the receipts so its ID is not burnt",
|
|
"encodes the receipt payload so the host can read what changed",
|
|
"creates, renames and drops tables with stable internal identifiers and one revision step each",
|
|
"adds typed columns, renames them without touching identifiers and never uses a label in SQL",
|
|
"validates labels by length, characters and case-insensitive uniqueness",
|
|
"refuses type changes, unknown operations, expressions and unknown types",
|
|
"encodes typed defaults as literals and survives hostile defaults",
|
|
"enforces required columns and refuses unique defaults that would collide",
|
|
"adds a unique column through a unique index and refuses duplicates atomically",
|
|
"drops a column by rebuilding the table and loses exactly what the preview reported",
|
|
"never hands out a row ID again after a column drop rebuilds the table",
|
|
"keeps the row ID counter when a column drop rebuilds a table emptied by deletes",
|
|
"leaves the original table, data and revision intact when a rebuild fails midway",
|
|
"previews exact effects and dependent data loss and changes nothing",
|
|
"refuses a stale expected revision with the current revision and applies nothing",
|
|
"keeps finite limits on tables and columns",
|
|
"migrates a database made before the catalog existed on its first schema change",
|
|
"inserts bound rows atomically with defaults, required and unique checks",
|
|
"updates by explicit IDs and by filter and bumps only the data revision",
|
|
"deletes by IDs or filter and refuses broad, empty or oversized selections",
|
|
"previews exact count, sample and conflicts without changing anything",
|
|
"refuses a changed revision and never re-evaluates a filter against new rows",
|
|
"applies exactly one of two proposals made on the same revision",
|
|
"replays a row operation by ID and refuses another request under the same ID",
|
|
"leaves no change when the process dies before commit and finds the receipt after commit",
|
|
"reserves the row id label so no column can shadow it",
|
|
"keeps a row table's data across a column drop that rebuilds it",
|
|
"reads selected columns with stable row IDs and typed JSON values",
|
|
"filters with bounded AND/OR trees and every operator, matching a reference evaluator on random trees",
|
|
"escapes LIKE wildcards in text filters",
|
|
"keeps NULL semantics: comparisons never match NULL and is-null finds it",
|
|
"sorts with a stable row ID tie-break and pages through a cursor that stops at a revision change",
|
|
"counts, sums, averages and bounds groups of aggregates",
|
|
"reports a real sum or average that overflows as the typed arithmetic error",
|
|
"never lets a label, operator or value reach SQL as text",
|
|
"honours hard limits on page size, filter depth, conditions, in-lists, sort keys and result bytes",
|
|
"stops a query when the context is cancelled or the deadline passes",
|
|
"encodes all five types as JSON and writes 64-bit integers as strings beyond 2^53",
|
|
"orders datetimes chronologically across fractional seconds and offsets",
|
|
"creates one private WAL database file named by the host resource ID",
|
|
"never lets an opaque ID or a name reach outside the storage directory",
|
|
"refuses a symbolic link as storage directory, database file or ledger",
|
|
"is idempotent by operation ID and never creates a second database",
|
|
"serializes concurrent creation of one operation into one database",
|
|
"recovers creation after a crash on either side of the file, and hides half-built files",
|
|
"renames only the named database and replays a renamed operation without effect",
|
|
"reports an unknown database and creates nothing for it",
|
|
"honours the busy timeout and the per-operation deadline, then succeeds once the lock is gone",
|
|
"encodes its receipts so the host can read them",
|
|
"writes a header and one record per row with RFC 4180 quoting, UTF-8 and the documented value forms",
|
|
"prefixes text cells and labels that a spreadsheet would run, never numbers",
|
|
"honours columns, the row identifier column, filter, sort and the row limit of the query",
|
|
"reads one snapshot: writes that commit while the export streams are not in it, and are not blocked by it",
|
|
"streams a large table row by row with bounded memory",
|
|
"fails cleanly past the row or byte bound and keeps the bound finite by default",
|
|
"stops on cancellation, on its deadline and on a failing destination, and reports each",
|
|
"does not change the database it reads",
|
|
"records the current format of a new store and migrates nothing",
|
|
"migrates every database in its own transaction, records the version last and repeats as a no-op",
|
|
"leaves a database whose step fails exactly as it was and resumes on the next run",
|
|
"refuses data in a newer format, a downgrade and a version it has no path to, and writes nothing",
|
|
"leaves no pending line for a change the add-on refused, so the same ID applies the corrected request",
|
|
"starts the real executable through the authenticated handshake and refuses unauthenticated callers",
|
|
"creates a database under the host-assigned ID and lists it only for people who may read it",
|
|
"drops the reservation when the addon refuses the name, and leaves no database",
|
|
"drops a reservation at reconcile when the crash came before the database was created",
|
|
"commits a reservation at reconcile when the crash came after the database was created",
|
|
"never exposes a database that has no host record",
|
|
"renames one database by operation, replays safely, and leaves every other database alone",
|
|
"rejects an undeclared tool, a forged addon binding and an unknown resource",
|
|
"keeps databases and operation receipts across an addon restart",
|
|
"fails closed when the addon cannot answer, and drops only for an addon that is not installed",
|
|
"creates a database from a chat proposal that only the proposer's session confirms",
|
|
"settles reservations at bootstrap by asking the real addon and keeps those of pending proposals",
|
|
"reads and mutates rows with the exact preview, refuses wrong actions and keeps receipts across a restart",
|
|
"declares the row tools and refuses a row tool the manifest does not name",
|
|
"changes the schema as the owner, shows data loss in the preview and refuses an editor at the host and the addon",
|
|
"rejects a stale schema revision, replays an operation and keeps receipts across a restart",
|
|
"declares the schema tools and refuses any schema tool the manifest does not name",
|
|
"applies row changes only on the proposer's confirmation and rejects a proposal whose database moved",
|
|
"offers the manifest tools to a permitted user and nothing to a user without the feature or after revocation",
|
|
"stores every change as a pending proposal and applies it only on the proposer's own session, exactly once",
|
|
"keeps the roles of the host for tool calls and rejects forged fields before the owner sees them",
|
|
"lists at most the bound of pending proposals and refuses more than the user's quota"
|
|
]
|
|
},
|
|
"tables-tools": {
|
|
"kind": "shell",
|
|
"commands": [
|
|
[
|
|
"sh",
|
|
"scripts/addons/tables_tools.sh"
|
|
]
|
|
],
|
|
"cases": [
|
|
"unit: tools: the namespace is the brokered add-on tool names only",
|
|
"unit: tools: a proposal result of an add-on tool gives its identifier and nothing else",
|
|
"unit: tools: other kinds, other tools and malformed identifiers give no card",
|
|
"unit: tools: the stored history keeps the reference of a proposal and no row data",
|
|
"unit: tools: the card facts come from the stored proposal and never from model text",
|
|
"unit: tools: stale, expired, blocked and settled proposals cannot be decided",
|
|
"unit: tools: a confirmation names the displayed proposal and its digest and nothing a model supplied",
|
|
"unit: tools: the add-on tools switch is offered only when an add-on offers tools",
|
|
"go: accepts the Tables definitions and classifies every model-facing tool",
|
|
"go: keeps the schema bytes of a parsed manifest equal to what the runtime echoes back",
|
|
"go: rejects a definition that declares an identity, role, approval or operation property",
|
|
"go: rejects an undeclared tool, a repeated tool, an unknown kind and a missing or unbounded schema",
|
|
"go: binds one actor to an executor and serves tools through the broker only",
|
|
"go: refuses to bind an executor when the owner denies the actor",
|
|
"go: routes the add-on namespace to the broker and never to another executor",
|
|
"go: never offers or runs a tool of an MCP session under the add-on namespace",
|
|
"go: reads the opt-in once and answers a surface that has no broker with a typed rejection",
|
|
"go: takes the actor from the trusted request context only",
|
|
"go: classifies every source file that discovers or executes tools",
|
|
"go: flags source that hands sessions to the agent library without the namespace filter",
|
|
"go: installs the namespace filter wherever sessions reach the agent library",
|
|
"go: does not offer a session tool of the add-on namespace to the job model",
|
|
"go: names a reason and an enforcement for every rejection and an actor for every route, with real files",
|
|
"go: keeps the table of the Tables documentation in step with the matrix",
|
|
"go: lets only the brokered consumers import the adapter",
|
|
"go: has no add-on tool and no add-on route in the admin assistant catalog",
|
|
"go: discovers namespaced tools with schemas from the manifest for enabled running addons only",
|
|
"go: offers nothing for a disabled, stopped or failed addon and nothing when the owner cannot answer",
|
|
"go: has no tool for sharing, deleting a database, purging retained data or approving",
|
|
"go: drops a definition whose namespaced name is not a valid function name or does not fit",
|
|
"go: reads through the gateway with the immutable actor, the listed generation and the resource taken out of the arguments",
|
|
"go: refuses an oversized result instead of truncating it",
|
|
"go: returns file results as private artifact references with no bytes",
|
|
"go: passes a denial, an outage and an unknown outcome through unchanged",
|
|
"go: turns a row change into a proposal reference and never applies",
|
|
"go: proposes schema changes under the schema action and creation with no resource",
|
|
"go: gives every call its own operation ID so one call can never replay another",
|
|
"go: reports a proposal outage with the typed error and no reference",
|
|
"go: rejects forged identity, role, approval and operation fields before anything reaches the owner",
|
|
"go: rejects approval aliases, undefined tools and names outside the namespace",
|
|
"go: rejects arguments that are not exactly one bounded object with known, typed properties",
|
|
"go: has no way to confirm, cancel or resolve a proposal",
|
|
"go: uses the actor of each call and nothing a previous call left behind",
|
|
"go: refuses an actor without a user or credential before any call",
|
|
"go: serves the real gateway type as its backend",
|
|
"go: lists the caller's own pending proposals the same from the owner and every forwarding frontend",
|
|
"go: offers the manifest tools to a permitted user and nothing to a user without the feature or after revocation",
|
|
"go: stores every change as a pending proposal and applies it only on the proposer's own session, exactly once",
|
|
"go: keeps the roles of the host for tool calls and rejects forged fields before the owner sees them",
|
|
"go: lists at most the bound of pending proposals and refuses more than the user's quota",
|
|
"proposals: a tool call in chat stores a pending proposal and the card shows the host record, not the model text",
|
|
"proposals: confirming in the card applies the change exactly once and a repeat returns the stored receipt",
|
|
"proposals: row changes show the exact count and a bounded sample, and nothing changes until the person confirms",
|
|
"proposals: cancel withdraws the proposal and nothing is applied",
|
|
"proposals: an expired proposal is disabled in the card and the host refuses a late confirmation",
|
|
"proposals: forged fields and approval names in a tool call create no proposal",
|
|
"proposals: a user whose add-ons feature is withdrawn sees no data and the host answers no",
|
|
"proposals: logging out clears the card and leaves no data in the stored conversation",
|
|
"go: gives the model an error result that says the request was invalid, for a read and for a change",
|
|
"go: keeps an outage an error, never the refused result"
|
|
]
|
|
},
|
|
"tables-admin": {
|
|
"kind": "ginkgo",
|
|
"commands": [
|
|
[
|
|
"go",
|
|
"test",
|
|
"-count=1",
|
|
"-p",
|
|
"2",
|
|
"-tags",
|
|
"auth",
|
|
"./tests/addons/tablesadmin",
|
|
"-ginkgo.json-report=../../../.cache/addons/logs/tables-admin.json"
|
|
]
|
|
],
|
|
"report": ".cache/addons/logs/tables-admin.json",
|
|
"cases": [
|
|
"keys a reference by user, conversation and add-on, bounds it per user and in total and expires what is unused",
|
|
"is durable, held by one process, never resets a corrupt file and stops writing after a failed sync",
|
|
"serves concurrent users without losing a reference",
|
|
"keeps the newest bounded number, validates them on load and remaps them with the owner",
|
|
"creates private databases by the person's own action, once per operation, and lists them only for their owner",
|
|
"keeps the owner, editor and viewer matrix on the UI routes and shows each person only their own role",
|
|
"shares whole databases by immutable account ID behind a bounded picker that tells nothing else",
|
|
"keeps sharing disabled in local-owner mode with a typed answer and no named users",
|
|
"waits for a revoked user's admitted work and cancels it before acknowledging the revocation",
|
|
"answers every typed denial exactly as the owner does and carries every mutation to the owner",
|
|
"reports an unknown outcome with the original operation ID and leaves reads plainly unavailable when the owner cannot be reached",
|
|
"answers the sharing denial of local-owner mode the same from a frontend",
|
|
"deletes the data, the grants and the pending proposals only on the owner's typed confirmation and keeps the add-on installed",
|
|
"stops and waits for admitted work of every user before it asks the add-on to delete",
|
|
"makes the add-on refuse its delete tool under every action but the host's delete action",
|
|
"never offers the delete tool to a model, a proposal, a typed read or an agent",
|
|
"denies a stale tab: the generation and the revision the owner saw decide, and nothing is removed",
|
|
"finishes or undoes a deletion that a crash interrupted at every step",
|
|
"keeps the delete tool out of the model tools and their definitions",
|
|
"refuses an admin tool that is also a model tool, has a definition, or is not mapped",
|
|
"documents every route, every emitted field and every typed answer in the Swagger spec",
|
|
"lists every route in the instructions registry, the feature registry and the documentation, with no MCP tool for any",
|
|
"keeps one selection per user, conversation and add-on, across people, conversations and restarts",
|
|
"lets a tool call omit the database in a conversation and resolves it at the owner with typed errors",
|
|
"withdraws the management and the tool path while the add-on is disabled and restores them on enable",
|
|
"answers a revoked, deleted or tampered reference like an unknown database and never reuses it",
|
|
"applies schema and row changes under the roles of the host, once per operation, with a receipt and no proposal",
|
|
"refuses crafted writes by a viewer, an editor's schema change, a revoked editor and an installation administrator",
|
|
"carries a UI change to the owner from a forwarding frontend and answers as the owner does",
|
|
"exports a table with exact bytes and attachment headers over real HTTP and shows no one else the file",
|
|
"keeps a shared database's file private, applies the person's own filter and sort, and denies after the grant is withdrawn",
|
|
"serves the same bytes and headers through a forwarding frontend, and fails the same way for a stranger",
|
|
"answers a result past the export limit as data with no file",
|
|
"binds an output handle to its operation, person and database",
|
|
"fails a truncated, grown or vanished stream and never serves it",
|
|
"fails the transfer when the store cannot write, and when the source is revoked before completion",
|
|
"expires the file only, enforces the quota per person and leaves the database as it was"
|
|
]
|
|
},
|
|
"tables-ui": {
|
|
"kind": "shell",
|
|
"commands": [
|
|
[
|
|
"sh",
|
|
"scripts/addons/tables_ui.sh"
|
|
]
|
|
],
|
|
"cases": [
|
|
"unit: resources: every call carries this add-on and its generation and nothing the add-on chose",
|
|
"unit: resources: an operation identifier chosen by the caller is kept across a retry",
|
|
"unit: resources: nothing is sent once the add-on is withdrawn",
|
|
"unit: resources: a malformed identifier is refused before any request",
|
|
"unit: resources: the request of each call names the route, the method and the own-session confirmation",
|
|
"unit: resources: an unknown operation and a body the host did not shape are refused",
|
|
"unit: resources: typed answers of the host keep their type for the page",
|
|
"unit: resources: the client of a stale answer is told it is stale",
|
|
"unit: resources: a typed read names the resource the person chose and the client sends it",
|
|
"unit: resources: a typed read always carries an operation identifier the owner accepts",
|
|
"unit: resources: the conversation header goes on a chat request that uses add-on tools, and only a well-formed one",
|
|
"unit: batch: typed rows become wire rows and an untouched optional column is left to its default",
|
|
"unit: batch: every cell error is named by row and column and nothing is sent",
|
|
"unit: batch: steps stay inside the add-on bounds",
|
|
"unit: batch: the selection toggles by row identifier and survives paging",
|
|
"unit: errors: each answer of the host gets its own words and recovery",
|
|
"unit: codecs: text keeps what was typed, bounds it, and null is explicit",
|
|
"unit: codecs: integers are exact up to 64 bits and never silently rounded",
|
|
"unit: codecs: reals are finite numbers",
|
|
"unit: codecs: booleans are true, false or empty for an optional column",
|
|
"unit: codecs: datetimes are read as UTC and sent as RFC 3339",
|
|
"unit: codecs: an unknown column type is refused",
|
|
"unit: codecs: the editor round-trips stored values",
|
|
"unit: codecs: grid text and the unchanged-field test",
|
|
"unit: codecs: a datetime with a fraction of a second is not rewritten by editing another field",
|
|
"unit: codecs: datetimes are compared as instants and offsets are normalised",
|
|
"unit: filters: operators follow the column type",
|
|
"unit: filters: a leaf, a list and the null tests are built from typed values",
|
|
"unit: filters: a condition that cannot be sent is an error, never dropped",
|
|
"unit: query: the arguments are the tool schema and nothing else",
|
|
"unit: query: pages go forward by the add-on cursor and back by the ones kept",
|
|
"unit: query: a column header cycles ascending, descending and none",
|
|
"unit: i18n: every language of the host has every key of the English bundle and nothing else",
|
|
"unit: i18n: a translation keeps the placeholders of the English text and carries no markup",
|
|
"unit: build: the bundle is plain JavaScript that names nothing it does not define",
|
|
"unit: build: the module exports createAddon and imports nothing",
|
|
"unit: render: createAddon returns the page, the declared component, a chat action and dispose",
|
|
"unit: render: the list, one database and the picker draw their loading state without a host",
|
|
"unit: render: what the page read is emptied when the add-on is withdrawn, by signal and by dispose",
|
|
"unit: retry: a read that met an unavailable add-on is tried again and then succeeds",
|
|
"unit: retry: it gives the last error back after the bound and never loops",
|
|
"unit: retry: a refusal, a stale answer or an unknown outcome is never repeated",
|
|
"unit: retry: a withdrawn add-on stops the waiting and the reads",
|
|
"go: applies schema and row changes under the roles of the host, once per operation, with a receipt and no proposal",
|
|
"go: refuses crafted writes by a viewer, an editor's schema change, a revoked editor and an installation administrator",
|
|
"go: carries a UI change to the owner from a forwarding frontend and answers as the owner does",
|
|
"tables-ui: a new database is private to its owner and a second person sees nothing of it",
|
|
"tables-ui: the owner builds a schema and rows, shares by name and each role gets its own controls",
|
|
"tables-ui: typed editors, structured filters, sort, paging and bounded batches work on real rows",
|
|
"tables-ui: editing another column leaves a datetime with a fraction of a second byte-identical",
|
|
"tables-ui: a revoke while a person is editing denies the next save and the page says it is unavailable",
|
|
"tables-ui: an installation administrator sees no database of other people and has no data privilege",
|
|
"tables-ui: deleting a database shows the warnings, needs the typed name and removes data and shares",
|
|
"tables-ui: a tab of an older generation is denied after an upgrade and after a disable",
|
|
"tables-ui: Select database keeps one database for each person and conversation and a tool call uses it",
|
|
"tables-ui: the pages work by keyboard, at 400 pixels and in the light and dark themes",
|
|
"tables-ui: logging out clears what was read and the next person on the same tab sees none of it",
|
|
"tables-ui: in local-owner mode sharing is disabled and the owner still manages databases"
|
|
]
|
|
},
|
|
"tables-csv": {
|
|
"kind": "shell",
|
|
"commands": [
|
|
[
|
|
"sh",
|
|
"scripts/addons/tables_csv.sh"
|
|
]
|
|
],
|
|
"cases": [
|
|
"unit: artifacts: only a host identifier names a file, and the only link is the host route",
|
|
"unit: artifacts: the card offers a download only for a complete file that has not expired",
|
|
"unit: artifacts: sizes are written with a binary unit",
|
|
"unit: artifacts: a tool result keeps well formed identifiers of its own kind only, at most four",
|
|
"unit: export: the view becomes the arguments of the tool and nothing a page or a cursor",
|
|
"unit: export: the answer is a file, or the reason there is none",
|
|
"go: writes a header and one record per row with RFC 4180 quoting, UTF-8 and the documented value forms",
|
|
"go: prefixes text cells and labels that a spreadsheet would run, never numbers",
|
|
"go: honours columns, the row identifier column, filter, sort and the row limit of the query",
|
|
"go: reads one snapshot: writes that commit while the export streams are not in it, and are not blocked by it",
|
|
"go: streams a large table row by row with bounded memory",
|
|
"go: fails cleanly past the row or byte bound and keeps the bound finite by default",
|
|
"go: stops on cancellation, on its deadline and on a failing destination, and reports each",
|
|
"go: does not change the database it reads",
|
|
"go: answers with one operation-bound CSV output whose bytes the handle streams exactly once",
|
|
"go: refuses a handle from another user, another operation, another database or after expiry, and removes expired files",
|
|
"go: keeps a handle for a retry until the stream completed",
|
|
"go: reports a result past the limit as data without an output, and leaves no file",
|
|
"go: removes the staged file when the export fails and bounds what stays staged",
|
|
"go: is a read that needs the read action and refuses unknown fields and mutation arguments",
|
|
"go: serves the bytes on the protocol output route to the matching envelope only",
|
|
"go: exports a table with exact bytes and attachment headers over real HTTP and shows no one else the file",
|
|
"go: keeps a shared database's file private, applies the person's own filter and sort, and denies after the grant is withdrawn",
|
|
"go: serves the same bytes and headers through a forwarding frontend, and fails the same way for a stranger",
|
|
"go: answers a result past the export limit as data with no file",
|
|
"go: binds an output handle to its operation, person and database",
|
|
"go: fails a truncated, grown or vanished stream and never serves it",
|
|
"go: fails the transfer when the store cannot write, and when the source is revoked before completion",
|
|
"go: expires the file only, enforces the quota per person and leaves the database as it was",
|
|
"go: serves identical bytes and headers from every replica and denies every other way in",
|
|
"tables-artifacts: the person exports the view they see and downloads exact bytes with attachment headers",
|
|
"tables-artifacts: another person is denied exactly like an unknown file, shared or not",
|
|
"tables-artifacts: a viewer exports what they may read and withdrawing the share ends the download",
|
|
"tables-artifacts: a result past the export limit gives a message and no file",
|
|
"tables-artifacts: the chat draws the host card for an export and stores only its identifier",
|
|
"tables-artifacts: a person at the file quota is told so and no file is made",
|
|
"tables-artifacts: in local-owner mode the owner exports and downloads with no account"
|
|
]
|
|
},
|
|
"recovery": {
|
|
"kind": "shell",
|
|
"commands": [
|
|
[
|
|
"sh",
|
|
"scripts/addons/recovery.sh"
|
|
]
|
|
],
|
|
"cases": [
|
|
"unit: recovery: the owner's typed refusals keep their type and nothing else is invented",
|
|
"unit: recovery: the banner never reads an unknown state as ready",
|
|
"unit: recovery: upgrade progress follows the journaled phases",
|
|
"unit: recovery: the verification state is a word before it is a colour",
|
|
"unit: recovery: every refusal has words, and an unknown outcome keeps its own",
|
|
"unit: recovery: every locale carries the same recovery keys as English",
|
|
"unit: recovery: a restore needs a stopped add-on, the typed ID and, from another mode, an account",
|
|
"unit: recovery: a purge needs a scope and an add-on that is not running",
|
|
"unit: recovery: the client sends the operation as the confirmation header and types the refusals",
|
|
"go: backs up, publishes the package, migrates, checks health and publishes the generation in that order",
|
|
"go: undoes a failure at every journal phase before the publication and puts the old generation back on its own data",
|
|
"go: finishes an upgrade whose publication was made when a later step failed",
|
|
"go: applies one rule after a restart at any phase: unpublished is undone, published is finished",
|
|
"go: refuses a changed trusted identity and an older data format before it stops or writes anything",
|
|
"go: keeps the add-on unavailable in needs-recovery after a failed migration to a new format and retains the package and the recovery copy",
|
|
"go: restores the backup itself when a migration that keeps the format fails halfway",
|
|
"go: keeps a running add-on unavailable and recoverable when the backup cannot be verified at rollback",
|
|
"go: copies a WAL database consistently with a manifest, digests, restricted permissions and the owner state",
|
|
"go: holds admission and invalidates pending proposals for the add-on while it copies",
|
|
"go: reports a corrupt backup and refuses to use it",
|
|
"go: stops before copying when the storage is too small and leaves no partial backup",
|
|
"go: leaves no partial backup after a cancellation and starts the add-on again",
|
|
"go: starts the add-on again when the copy fails",
|
|
"go: keeps the only verified copy and the upgrade recovery copy under an explicit retention policy",
|
|
"go: never lets age or count remove the newest verified backup when retention is applied on demand",
|
|
"go: restores a local-owner backup to a named account through an explicit mapping",
|
|
"go: needs an administrator, the typed add-on ID, an explicit scope and an add-on that is not running",
|
|
"go: removes the data and its records but keeps the backups unless they are in the scope",
|
|
"go: touches no other add-on",
|
|
"go: finishes a purge that stopped after its journal was written",
|
|
"go: clears needs-recovery when the data it described is purged",
|
|
"go: refuses a backup when the policy cannot drain admitted work",
|
|
"go: refuses a backup of another add-on and touches neither data nor access",
|
|
"go: never lets a manual backup of half migrated data displace the pinned recovery copy",
|
|
"go: puts the data and the owner state back, warns about lost writes and keeps the replaced data as a recovery copy",
|
|
"go: counts the operations applied after the backup as lost writes",
|
|
"go: does not give back access that was taken away or whose account is gone",
|
|
"go: survives a restart that forgets the in-memory state: the revocation log is durable",
|
|
"go: refuses a running add-on, a stranger, an unknown backup and an invalid mapping without changing anything",
|
|
"go: refuses a backup of another trusted identity or of a newer data format",
|
|
"go: resumes or rolls back a restore that stopped at each phase, by one rule",
|
|
"go: holds the resources of one add-on and leaves another add-on alone",
|
|
"go: cancels admitted work and reports a drain that did not finish",
|
|
"go: restores grants through the account directory and the lowerings since the backup, never beyond them",
|
|
"go: keeps a bounded durable log of lowered access",
|
|
"go: keeps a revocation however many later lowerings of another person follow",
|
|
"go: restores the data but no access when the history may have lost a lowering",
|
|
"go: reads a store that is full of lowerings as one whose history may be cut",
|
|
"go: applies a lowering made after the export whatever time the backup is given",
|
|
"go: refuses a change that was authorized just before the hold began",
|
|
"go: cancels a pending proposal and leaves an executing one outcome-unknown after a restore",
|
|
"go: forgets the records of one add-on and no other",
|
|
"go: maps an owner on a restore to a local-owner store only when nothing named is in it",
|
|
"go: migrates the ownership of a stopped store with a backup and an explicit mapping and refuses a populated downgrade",
|
|
"go: records the current format of a new store and migrates nothing",
|
|
"go: migrates every database in its own transaction, records the version last and repeats as a no-op",
|
|
"go: leaves a database whose step fails exactly as it was and resumes on the next run",
|
|
"go: refuses data in a newer format, a downgrade and a version it has no path to, and writes nothing",
|
|
"go: makes a backup only for an administrator's own browser session and lists it",
|
|
"go: restores with warnings and does not give back a share that was revoked after the backup",
|
|
"go: restores only a backup of the add-on in the route and touches nothing otherwise",
|
|
"go: gives a forwarding frontend the same typed answers as the owner",
|
|
"go: purges only with the typed ID, a stopped add-on and an explicit scope, and touches nothing else",
|
|
"go: is never reachable by a model: no tool, no declared name and no route for an API key",
|
|
"go: upgrades an add-on with data through a backup and a migration and keeps its databases",
|
|
"go: undoes an upgrade whose package does not start and runs the old generation on its own data",
|
|
"go: hands retained data only to the same trusted source on a reinstall",
|
|
"go: documents every route and every emitted field in the Swagger spec, the instructions and the feature registry",
|
|
"recovery: an administrator backs up from the manage sheet and the backup is listed as verified",
|
|
"recovery: a person and a key cannot back up, restore or purge, and only the owner session of an administrator can",
|
|
"recovery: the restore dialog warns, asks for the typed ID and a restore does not give back a revoked share",
|
|
"recovery: a second backup, the sole recovery copy is kept and the keyboard reaches every action",
|
|
"recovery: the page shows a needs-recovery banner with restore and purge as the actions (status mocked)",
|
|
"recovery: a purge needs a scope, the typed ID and a stopped add-on, and removes the data and its shares"
|
|
]
|
|
},
|
|
"packaging": {
|
|
"kind": "shell",
|
|
"commands": [
|
|
[
|
|
"sh",
|
|
"scripts/addons/package_test.sh"
|
|
]
|
|
],
|
|
"cases": [
|
|
"go: joins every enabled platform leg into one verified index",
|
|
"go: never creates a partial index when an enabled platform has no leg",
|
|
"go: refuses duplicate legs, local-check legs, other versions and extra platforms",
|
|
"go: refuses a merged layout that lost a platform after the merge",
|
|
"go: builds a deterministic platform layout with executable, ui and manifest layers",
|
|
"go: restores the validated executable mode on extraction",
|
|
"go: refuses a platform that the matrix has not enabled unless it is a local check",
|
|
"go: refuses an invalid version, an existing layout and an empty executable",
|
|
"go: rejects a package without its entrypoint",
|
|
"go: rejects a declared UI whose layer or files are missing",
|
|
"go: rejects a package without a required runtime library",
|
|
"go: rejects a manifest whose platform differs from the image",
|
|
"go: rejects an image config or annotation of another platform",
|
|
"go: rejects a manifest version that differs from the release version",
|
|
"go: rejects another artifact type",
|
|
"go: rejects unexpected layers, roles and layer media types",
|
|
"go: rejects an unexpected file in the executable layer",
|
|
"go: rejects a blob whose bytes differ from its digest",
|
|
"go: rejects a receipt that does not match the image",
|
|
"go: rejects invalid extraction permissions",
|
|
"go: rejects a UI file that is executable or outside the declared directory",
|
|
"go: rejects traversal paths, links and duplicates",
|
|
"go: rejects a UI that bundles its own React runtime",
|
|
"go: rejects an icon that is not an image of its type",
|
|
"go: rejects an invalid platform layout marker or index",
|
|
"go: moves development forward and leaves it alone for an older commit",
|
|
"go: accepts a diverged branch head and refuses one commit with two contents",
|
|
"go: moves latest only to a newer stable version",
|
|
"go: refuses reserved or foreign alias names and unpublished digests, leaving aliases unchanged",
|
|
"go: promotes a branch channel under its hashed name",
|
|
"go: treats a force-pushed branch as the new truth for a push to the same ref",
|
|
"go: blocks the alias for anything but a push to the channel's own ref",
|
|
"go: refuses development when its commit is unreachable, even for a push",
|
|
"go: fails on any git error that is not a plain not-ancestor answer",
|
|
"go: tells an unreachable commit from a plain not-ancestor",
|
|
"go: accepts the add-on namespace and refuses every other go-skynet repository",
|
|
"go: reads a YAML list and refuses JSON, unknown fields and a second document",
|
|
"go: refuses missing and backend repositories before any request",
|
|
"go: pushes platform digests then the index, and a retry is digest-identical",
|
|
"go: rejects overwriting an immutable version with different content",
|
|
"go: adopts published content only for the same version and commit",
|
|
"go: refuses reserved aliases and mismatched tags as immutable tags",
|
|
"go: publishes nothing from a partial or local-check layout",
|
|
"go: fails closed when no platform is enabled, the file is absent or empty",
|
|
"go: rejects enabled platforms without a native runner or check, duplicates and unknown fields",
|
|
"go: prints the enabled platforms with their native runners",
|
|
"go: ships the checked-in matrix with every platform disabled until its native check passes",
|
|
"go: renders digest-pinned entries with an explicit add-on signer identity",
|
|
"go: renders an entry for every first-party add-on from its own template",
|
|
"go: refuses missing inputs, backend repositories, bad channels and unknown placeholders",
|
|
"go: carries placeholders only: no fabricated URL, registry or namespace",
|
|
"go: never publishes from a pull request, whatever the ref",
|
|
"go: maps master alone to development and publishes the commit tag",
|
|
"go: never publishes from a branch push, whatever the branch is named",
|
|
"go: keeps reserved names out of the branch namespace",
|
|
"go: separates refs that normalize to the same label",
|
|
"go: bounds empty, Unicode and very long branch names",
|
|
"go: lets a tag push prepare the immutable version and never move latest",
|
|
"go: promotes latest only for a published, stable, non-draft release",
|
|
"go: rejects unknown events and a malformed commit",
|
|
"go: prints the decision as key=value lines",
|
|
"go: accepts the checked-in workflow",
|
|
"go: rejects pull_request_target",
|
|
"go: rejects secrets in a pull request validation job",
|
|
"go: rejects id-token write outside the publishing job",
|
|
"go: rejects a registry login or publish in an untrusted job",
|
|
"go: rejects publish that does not wait for every platform leg",
|
|
"go: rejects publish that can run after a failed leg",
|
|
"go: rejects publish that does not need validate",
|
|
"go: rejects a package leg that does not need validate",
|
|
"go: rejects a validate job that cannot stop the release",
|
|
"go: rejects a package or promote job that runs after a failed validate",
|
|
"go: keeps validate unprivileged on every event",
|
|
"go: rejects promotion that does not wait for signing",
|
|
"go: rejects alias promotion before signing",
|
|
"go: rejects an alias command inside the publishing job",
|
|
"go: rejects a literal latest tag",
|
|
"go: rejects backend registries and backend workflows",
|
|
"go: rejects a signer identity that is a pattern or the backend workflow",
|
|
"go: rejects signing by tag or without referrers and the new bundle format",
|
|
"go: rejects missing serialization per channel",
|
|
"go: rejects publication that is shared between add-ons",
|
|
"go: rejects a workflow that names one add-on by path or skips an add-on in the matrix",
|
|
"go: rejects a plan that does not refuse an add-on without an enabled platform",
|
|
"go: rejects a plan that does not fail closed on missing configuration",
|
|
"go: rejects a plan that does not exit 1 for an add-on without an enabled platform on a publishing event",
|
|
"go: rejects a plan that treats any matrix error as no legs",
|
|
"go: rejects a repository rule that does not keep the configured repository for tables",
|
|
"go: rejects a publish or promote matrix that stops the other add-ons on a failure",
|
|
"go: rejects a publish job that downloads the layouts of other add-ons",
|
|
"go: rejects a promote job that does not check the digest format",
|
|
"go: derives a repository that the add-on tools accept for every add-on from the documented variable",
|
|
"go: fails on a publishing event when an add-on has no enabled platform",
|
|
"go: publishes when every add-on has an enabled platform",
|
|
"go: gives an add-on without an enabled platform no legs on an event that publishes nothing",
|
|
"go: fails on a missing or malformed platform file on every event",
|
|
"go: rejects a checkout of the pull request head or a persisted token",
|
|
"go: rejects write permission at workflow level and a literal platform matrix",
|
|
"go: rejects a publishing job without an environment or a gate",
|
|
"go: does not trust the backend workflow identity in the documented verification",
|
|
"go: installs the package built by package.sh and starts its executable",
|
|
"go: is refused when the signature carries another workflow identity",
|
|
"go: is refused when the owner policy names the backend workflow",
|
|
"go: is refused when the pinned digest is not the published image",
|
|
"go: gives identical digests for two builds of the same inputs",
|
|
"go: refuses a platform the matrix does not enable and a missing executable of another platform",
|
|
"package.sh builds and verifies a local check layout",
|
|
"package.sh refuses a platform the matrix has not enabled",
|
|
"package.sh refuses an existing non-empty layout",
|
|
"package.sh requires its arguments",
|
|
"package.sh refuses an invalid version",
|
|
"package.sh builds and verifies the voice add-on for the host",
|
|
"package.sh refuses a foreign platform without an executable: tables",
|
|
"package.sh refuses a foreign platform without an executable: voice",
|
|
"package.sh refuses a foreign platform without an executable: face",
|
|
"package.sh refuses a foreign platform without an executable: fine-tuning",
|
|
"package.sh refuses a foreign platform without an executable: quantization",
|
|
"package.sh refuses a foreign platform without an executable: studio",
|
|
"package.sh refuses a foreign platform without an executable: talk",
|
|
"package.sh refuses a foreign platform without an executable for every add-on",
|
|
"package.sh builds Tables with cgo and the pure Go add-ons without",
|
|
"matrix fails closed while no platform is enabled",
|
|
"matrix fails closed without a file",
|
|
"channel.sh: a pull request never publishes",
|
|
"channel.sh: master publishes development",
|
|
"channel.sh: a branch push never publishes, even a branch named latest",
|
|
"channel.sh: a tag push prepares the version and moves no alias",
|
|
"channel.sh: a published stable release promotes latest",
|
|
"channel.sh: a pre-release never promotes latest",
|
|
"channel.sh: a draft release fails",
|
|
"channel.sh: an unknown event fails",
|
|
"channel.sh: a tag that is not a version fails",
|
|
"workflow policy accepts the checked-in workflow",
|
|
"workflow policy rejects pull_request_target",
|
|
"workflow policy rejects a publish job that does not wait for every leg",
|
|
"workflow policy rejects a validate job that cannot stop the release",
|
|
"scripts never push, tag, sign or log in",
|
|
"packaging files never reference backend registries or workflows"
|
|
]
|
|
},
|
|
"updates": {
|
|
"kind": "shell",
|
|
"commands": [
|
|
[
|
|
"sh",
|
|
"scripts/addons/updates.sh"
|
|
]
|
|
],
|
|
"cases": [
|
|
"unit: updates: a failed, unknown or unreadable check is never current",
|
|
"unit: updates: an upgrade is offered only for a candidate the owner confirmed, with a digest to pin",
|
|
"unit: updates: the owner's typed refusals keep their type and are final answers",
|
|
"unit: updates: the apps list marks an update beside the process state, never in place of it",
|
|
"unit: updates: times are shown as the reader's own and a bad time as nothing",
|
|
"unit: updates: the client sends check and upgrade as the administrator's own action and types the refusals",
|
|
"unit: updates: every locale carries the same update keys as English, and words for every state, reason and refusal",
|
|
"go: offers a digest-only change of the branch-fix-cache channel with an identical version label",
|
|
"go: offers a digest-only change of the development channel with an identical version label",
|
|
"go: offers a digest-only change of the latest channel with an identical version label",
|
|
"go: is up to date when the channel resolves to the installed digest",
|
|
"go: never switches the channel: another channel and other versions are not offered",
|
|
"go: selects the highest compatible greater version of the same major",
|
|
"go: does not cross a major version",
|
|
"go: does not move a stable install to a pre-release and orders pre-releases below their release",
|
|
"go: treats a lower version as nothing to offer",
|
|
"go: reports the same digest as up to date",
|
|
"go: reports a rewritten immutable version as an integrity error, never an update",
|
|
"go: names the host, SDK and data format ranges a candidate does not fit",
|
|
"go: refuses a candidate whose data format ends below the installed one",
|
|
"go: reports a platform that is not offered, and prefers the compatible version over a newer incompatible one",
|
|
"go: does not check the SDK range of a candidate that declares no UI",
|
|
"go: reports a failed library as check-failed with the last success, never as up to date",
|
|
"go: names an unavailable source credential and an unreachable library by class",
|
|
"go: reports an add-on the library no longer lists as check-failed",
|
|
"go: returns an error for an add-on that is not installed and for a canceled caller",
|
|
"go: answers a status read from the cache and never evaluates or fetches",
|
|
"go: serves a fresh answer from the cache and evaluates again when it is stale",
|
|
"go: marks a cached answer older than the time to live as stale",
|
|
"go: refreshes the library only on an explicit refresh and applies nothing",
|
|
"go: limits explicit refreshes to one per interval and says so",
|
|
"go: shares one check among concurrent callers",
|
|
"go: never lets an explicit refresh join a plain evaluation that is already in flight",
|
|
"go: keeps the work of a canceled caller from spoiling the answer of the others",
|
|
"go: bounds the cache and forgets the answer of a replaced package",
|
|
"go: redacts the library, channel and digests for a caller who is not an administrator",
|
|
"go: keeps the compatibility hint of an entry and refuses a malformed range",
|
|
"go: lists the releases of one add-on for every platform, from the cache, and refuses a failed library",
|
|
"go: names an unavailable credential reference as a credential failure inside the refresh failure",
|
|
"go: reports a digest-only change of a moving channel, applies nothing and offers the pinned upgrade",
|
|
"go: refuses a second operation ID for the same transition, in flight or done, and applies it once",
|
|
"go: runs concurrent requests with one operation ID once and gives each the same answer",
|
|
"go: serializes conflicting upgrades by the installed digest and refuses the loser without a record",
|
|
"go: refuses a candidate that is not the one the library resolves now",
|
|
"go: refuses an upgrade to the digest that is already installed",
|
|
"go: rechecks compatibility at execution and refuses an incompatible candidate",
|
|
"go: selects a newer immutable version and treats a rewritten version as an integrity error",
|
|
"go: keeps the last good generation when the candidate cannot be staged",
|
|
"go: never switches the library or channel, and a failed check is never up to date",
|
|
"go: lets an administrator refresh and everyone with the feature read a redacted status",
|
|
"go: shows the pending update in the apps list from the cache only",
|
|
"go: does not accept pins without an update checker or on another action",
|
|
"go: keeps the unpinned typed upgrade of an earlier release working",
|
|
"go: gives every caller with the feature the same status from every frontend, redacted for non-administrators",
|
|
"go: checks only for an administrator's own browser session, and applies nothing",
|
|
"go: upgrades only to the checked candidate, with the same typed refusals from every frontend, and never twice",
|
|
"go: runs two concurrent upgrades from two frontends once: the same ID shares the answer, another ID is a conflict",
|
|
"go: refuses an incompatible candidate and a library that cannot be read, with a typed answer",
|
|
"go: reports a lost upgrade as an unknown outcome with its original operation, and a lost status read or check as plainly unavailable",
|
|
"go: keeps the update actions out of the tools and names every field of the status in the Swagger spec",
|
|
"updates: a library with nothing newer is up to date, and a member sees no update mark",
|
|
"updates: a moved channel with the same version label is an update, in the list and as a pending mark",
|
|
"updates: a member, a key and an outsider cannot check or upgrade",
|
|
"updates: the dialog names the library, versions and digests, a cancel sends nothing, and the upgrade backs up and keeps the data",
|
|
"updates: two requests for the same transition under different operations run it once",
|
|
"updates: a page that is behind cannot upgrade over a newer installed package",
|
|
"updates: a candidate this host cannot run shows its reason and has no upgrade",
|
|
"updates: an unreachable library is a failed check, never up to date, and says when it was last read",
|
|
"updates: on a narrow screen the check is reachable and runs from the keyboard",
|
|
"go: ends the checks in flight when it is closed and refuses new ones"
|
|
]
|
|
},
|
|
"tables-acceptance": {
|
|
"kind": "shell",
|
|
"commands": [
|
|
[
|
|
"sh",
|
|
"scripts/addons/tables_acceptance.sh"
|
|
]
|
|
],
|
|
"cases": [
|
|
"go: reports an update only on a check, shows a member no digest, refuses a key and applies one pinned candidate with the data and grants kept",
|
|
"go: refuses a change prepared on an old schema or data revision from two tabs of two people and applies nothing",
|
|
"go: replays an operation ID as one receipt from every node, conflicts on a different request and never applies twice or under a new ID",
|
|
"go: settles a revocation that races a confirmation: one outcome, applied at most once, and no work after the revocation",
|
|
"go: separates owner, editor, viewer, administrator and stranger across the browser routes, the REST routes and the chat tool consumer",
|
|
"go: serves the browser module to every account with the feature and to nobody else, from the owner and each frontend",
|
|
"go: fails every blocked consumer explicitly and never serves add-on tools to it",
|
|
"go: is the administrator's own action on every node and never a key's, a member's or a tool's",
|
|
"go: refuses a corrupt backup and a restore that is not allowed, and leaves the data as it was",
|
|
"go: restores a verified backup: the data goes back, the add-on starts again and access follows the current accounts",
|
|
"go: denies the open tabs of a disabled add-on everywhere and serves them again, with the same data, when it is enabled",
|
|
"go: keeps data and grants when the add-on is removed and installed again, and refuses what the old generation prepared",
|
|
"go: denies the next call of a paused key on every node and accepts it again when resumed",
|
|
"go: denies the browser, the key and the chat everywhere when the add-ons feature is withdrawn",
|
|
"go: lowers an editor to a viewer for the next call everywhere and drops the proposals the editor still held",
|
|
"go: refuses the session and the key of a disabled account on every node",
|
|
"go: ignores actor, forwarding and authority headers and fields on every node",
|
|
"go: denies authority, role and approval fields in the arguments of every consumer and creates nothing",
|
|
"go: applies a proposal only on the confirmation of the proposer's own tab, with its digest, exactly once",
|
|
"go: keeps every acknowledged change and applies no change twice when the Tables process is killed in the middle of a batch",
|
|
"go: keeps every acknowledged change and applies no change twice when the owner is killed in the middle of a batch and restarted",
|
|
"go: blocks every other write while a confirmation is unresolved, keeps reading, and accepts writes again only after the owner role resolves it",
|
|
"go: fails every response type closed with the same typed answer from both frontends, runs nothing there and serves everything again after the restart",
|
|
"go: exports a CSV through a frontend and serves the same bytes from every node to its requester only",
|
|
"go: stops the downloads of a person whose access to the database was revoked, on every node, and keeps the owner's",
|
|
"go: denies downloads while the add-on is disabled and serves a complete file again when it is enabled",
|
|
"go: answers the refusal as invalid_request with status 400 on every route and node and changes nothing",
|
|
"go: does not consume the operation ID of a refused change",
|
|
"go: denies an expired file identically from every node and leaves the data and the backups untouched",
|
|
"go: withdraws a transfer held in flight when the add-on is disabled and leaves no downloadable file",
|
|
"go: reports a change that committed and lost its answer as unknown, finds it by receipt and replays the same receipt once",
|
|
"tables-acceptance: a member opens the databases and a grid through each non-owner frontend and the module comes from the owner by digest",
|
|
"tables-acceptance: an approval card from chat on one frontend applies once and the row shows on the other frontend",
|
|
"tables-acceptance: deep links keep the proxy path prefix on a non-owner frontend and survive a reload",
|
|
"tables-acceptance: the grid works by keyboard, at 400 pixels and in both themes on a non-owner frontend",
|
|
"tables-acceptance: the page says it is unavailable while the owner is gone and recovers on reload when it is back",
|
|
"tables-acceptance: after logout nothing of the database is left in the page or the stored chat",
|
|
"manifest: the evidence manifest names the platform, the commands, the package digests and every case"
|
|
]
|
|
}
|
|
}
|