chore(deps)(deps-dev): bump @babel/core from 7.29.0 to 7.29.7 in /core/landing#65
Closed
dependabot[bot] wants to merge 476 commits into
Closed
chore(deps)(deps-dev): bump @babel/core from 7.29.0 to 7.29.7 in /core/landing#65dependabot[bot] wants to merge 476 commits into
dependabot[bot] wants to merge 476 commits into
Conversation
…4 cleanup The brand-alignment commit (aa010a7) and the Brief 4 R4 vanilla-admin removal left 11 vitest files asserting against stale UI / files. This commit re-aligns each test with the current canonical state — no source behaviour changed; the production code already matches the new expectations. Touched test files (10 modified, 1 deleted): - __tests__/i18n.test.ts: hero.cta_primary moved from price-led ("Get Self-Host — $299") to demo-led ("Watch Demo" / "Demo İncele" / "Ver Demo"). - __tests__/PricingPage.test.tsx: Q6 PA collapsed the 3-tier pricing cards into a Pilot/PoC mailto CTA — assertions match the new `<section data-testid="pricing-page">` surface. - __tests__/Pricing.test.tsx: `<Pricing />` is now an explicit no-op stub (`Pricing.tsx` returns null); test guards against accidental re-introduction of the deprecated SKU grid. - __tests__/Footer.test.tsx: refund link removed from the global footer; only /privacy and /terms remain. - __tests__/CheckoutButton.test.tsx + ManageModal.test.tsx: `BILLING_ENABLED` defaults to false at module load (T-R03 fix #1 kill-switch). Tests now `vi.mock("@/lib/billing-flag", …)` so the Stripe path runs deterministically in jsdom. - __tests__/MarketplacePanel.test.tsx: Approve button is gated behind the explicit `permission-acknowledge` checkbox (Q9 / MP4); test ticks the checkbox before clicking Approve so onInstall fires. - __tests__/Privacy.i18n.test.tsx + Privacy.test.tsx: PrivacyPage is now an async Next.js 15 server component with a `searchParams: Promise<…>` prop. Tests await the server component directly and render the resolved JSX. - __tests__/Q11ErrorUx.test.ts: chat error tile contract moved from `app/panel/chat/page.tsx` (now a thin route wrapper) to `app/panel/chat/ChatClient.tsx` (Sprint 21 Faz C dynamic split). - __tests__/AdminDashboard.test.tsx: deleted — vanilla 032 admin HTML asserted by this file was removed in Brief 4 R4 (`core/backend/app/static/admin/index.html`); the Next.js admin under `app/admin/*` owns the surface and is exercised by Playwright. Result: `npm test` → 24 files / 112 passed / **0 failed** (was: 25 files / 90 passed / 26 failed; net delta ‑3 obsolete tests, +19 contract-aligned pass).
…cache
Brief 3 R4 ships the threading metadata that powers the panel sidebar
(pin, archive, search, sort-by-recent), plus the counter cache that
keeps the sidebar render off the chat_messages table.
Schema (alembic 0009_chat_threading)
- chat_sessions adds: pinned BOOL DEFAULT 0, archived_at DATETIME NULL,
last_activity_at DATETIME NOT NULL (backfilled from updated_at),
message_count INTEGER DEFAULT 0 (backfilled by COUNT() over
chat_messages). Indexes on last_activity_at + archived_at so the
sidebar's "active threads sorted by recency, archived hidden" query
is a single seek per tenant.
- batch_alter_table is used so SQLite can rewrite the table; the
NOT NULL flip on last_activity_at runs after the backfill UPDATE.
Model (app/db/models.py)
- ChatSession gains the four columns with sane defaults; existing
tests / fixtures continue to pass without explicit values.
API (app/api/chat.py)
- ChatSessionOut grows pinned / archived_at / last_activity_at fields.
- _session_out reads message_count from the counter cache when the
caller didn't pre-compute it.
- GET /v1/chat/sessions now accepts ?search=&include_archived= and
orders pinned first then by last_activity_at desc; pins always sit
on top of the rail.
- POST /v1/chat/sessions/{id}/pin?pinned=true|false toggles pin state.
- POST /v1/chat/sessions/{id}/archive sets archived_at (idempotent;
re-archive keeps the original timestamp).
- POST /v1/chat/sessions/{id}/unarchive clears archived_at.
- /v1/chat/completions bumps last_activity_at + message_count for the
user message AND the assistant reply (so the counter matches the
on-disk row count without a per-render COUNT()).
Tests
- tests/test_chat_threading.py — 8 new specs (default metadata,
pin toggle, archive idempotent + unarchive, list excludes archived
by default, pinned-first ordering, ?search= filter, completion
bumps both counters, 404 on unknown session).
- tests/test_q11_l14_alembic_roundtrip.py — `command.downgrade(cfg,
"-1")` now lands on 0008 (previous head) instead of 0007. Switch
to an explicit `0007_chat_sessions` target so the contract still
exercises the original 0008 → 0007 round-trip.
- tests/test_q12_l21_safe_expansion.py — same fix applied to the
10× cycle test for the same reason.
Full backend regression: 1845 passed / 0 failed / 10 skipped (was
1837 / 0; net +8 threading tests, two alembic round-trip targets
pinned). NO Cohere/Gemini text-API calls.
Brief 4 §9 R7 deliverable — production-like flow contracts that exercise the running compose stack (Caddy + landing + backend). Specs are gated behind `PLAYWRIGHT_PROD_STACK=1` so the default `npx playwright test` invocation against `next dev` skips them automatically. Helper - __tests__/playwright/helpers/prod-stack.ts: shared base URL, reachability ping (`requireProdStack`), and Caddy login helper (`loginThroughCaddy`). Honours `PLAYWRIGHT_BASE_URL` so CI can point at any deployed stack (`https://abs.acme.com`). Specs (run with the compose stack up) - prod_caddy_route_split.spec.ts (5 tests): `/` → landing, `/api/health` → landing, `/healthz` → backend (JSON), `/panel` → 308 → `/admin`, `/admin/login` → landing-served HTML. - prod_admin_login.spec.ts (3 tests): guest visit redirects to /admin/login; /auth/login sets the abs_session cookie via Caddy on the shared origin; admin lands on /admin/dashboard after login. - prod_admin_usage_renders.spec.ts (2 tests): /v1/admin/usage round-trips JSON via Caddy; /admin/usage page renders the Tremor chart shell (Recharts container or [data-tremor]). - prod_admin_settings_tabs.spec.ts (1 test): seven tabs (Identity / Providers / Vault / Billing / Email / Integrations / Danger zone) render and click flips ARIA-selected. - prod_setup_to_admin_e2e.spec.ts (3 tests): /setup is served by backend through Caddy; /v1/setup/status JSON; post-setup /admin/dashboard is owned by landing (no backend 404 from the deleted vanilla 032 admin). Run command: docker compose -f infra/docker-compose.yml up -d PLAYWRIGHT_BASE_URL=https://abs.local PLAYWRIGHT_PROD_STACK=1 \ npx playwright test prod_ Default `next dev` flow is unaffected — verified `npx playwright test prod_caddy_route_split --project=chromium-desktop` reports `5 skipped` when the flag is unset. NO Cohere/Gemini API calls.
Polish round R1+R2+R3+R4+R8 — 14-page browse review:
R1 — Founder PII (12+ files): "Enes" stripped from UI strings,
docs author lines, sprint artifacts; "/Users/eneseserkan/..." paths
replaced with Path(__file__).resolve().parents[3] in test_029.
New tests/test_no_founder_pii.py guards core/landing/, docs/, README.md.
R2/R3 — Sidebar URL inconsistencies (4 broken links + 3 routed 404s):
sidebar advertises canonical /admin/* (chat, meetings, transcription,
mcp-tools), Cascade renamed Sağlayıcılar. next.config.ts adds 308
redirects /admin/* → live /panel/* page so bookmarks survive. Active
highlight tracks the redirect equivalence map.
R4 — i18n: MarketplacePanel + WorkflowChatPanel localised TR (Sentezle,
Düzenle, Bekliyor, Yapılandırıldı...), sidebar group caps render via
toLocaleUpperCase('tr-TR') + lang=tr so İ keeps its dot.
R8 — Chat sample prompts: 4 internal prompts replaced with neutral
openers (İlk projemde sana nasıl yardım edebilirim?, Bu hafta ekibimin
yaptığı işleri özetle, Yeni müşteri görüşmesi için hazırlık, /help).
Tests: pytest 1845 → 1855 (+10), vitest 112 → 136 (+24).
R6 — Backend GET /v1/license/info combines /status + /demo-status into the single shape the Settings → Lisans tab now consumes. LicenseTab refactored: hardcoded "Solo / jwt-…12ab34cd / 2027-04-30" mock removed, useEffect+fetch lifecycle, masked JTI helper, activation form (textarea + POST /v1/license/activate, success toast clears the demo banner). 3 backend pytest (demo / licensed / invalid branches) + 6 vitest source guards (no legacy mock string, fetches /info, posts license_key, has activation textarea + button, JTI mask helper). R7 — Backend GET /v1/admin/providers/status returns capitalised label + configured boolean per cascade provider (no raw key on the wire). ProvidersTab refactored: id labels Capitalize → Groq/Cerebras/.../Anthropic via backend, status badge (Yapılandırıldı / Eksik), password input, provider-specific placeholders, Test button → "Henüz uygulanmadı" toast slot. 4 pytest (auth, 6 canonical providers, configured flag, no leak), 5 vitest source guards. Tests: pytest +7, vitest +11.
R5 — /admin/usage 7-Gün Claude Token Trendi: empty axes flagged as broken in founder browse. UsageClient now detects an all-zero or empty trend payload and renders a friendly "Henüz Claude çağrısı yok / İlk çağrıdan sonra trend burada görünecek." card instead of bare axes. R10 — Global Turkish 404: app/not-found.tsx ships brand-neutral "Sayfa bulunamadı" with lang=tr, robots noindex, and dual CTAs back to / and /admin/usage. 4 vitest source guards (title, lang, hrefs, robots). R9 — Test data reset: scaffold-only. Brief 4 R7 (commit 70c1518) shipped scripts/reset_test_data.py; auto mode cannot run --confirm without explicit founder approval (CLAUDE.md "Executing actions with care" + destructive op rule). artifacts/sprint_q12/polish_round_r9_…md captures the docker compose exec dry-run command, the promote step when the report looks correct, and the four post-purge verifications. Tests: vitest +4 (NotFoundPage). pytest unchanged.
The Q12-R1 multi-stage Dockerfile bakes only PORT=3000 into the runtime layer; without HOSTNAME=0.0.0.0 the standalone server.js binds to localhost only, and Caddy → landing:3000 hits ECONNREFUSED across the Docker bridge. Override via compose env so the fix lands without a Dockerfile rebuild round; future Dockerfile bump can fold this into the ENV block.
scripts/add_license_headers.py applied to: - 371 Python files (core/backend/app/, scripts/) - 135 TypeScript/TSX files (core/landing/app/,components/,lib/) Header format: Copyright (c) 2026 Automatia BCN. All rights reserved. Licensed under the Business Source License 1.1. Production use requires a Commercial License - see LICENSE. Change Date: 2030-05-07 -> Apache License, Version 2.0 Idempotent: re-running the script produces 0 new headers.
Closes 2 Dependabot alerts: - postcss XSS via unescaped </style> (medium) — fix in 8.5.10 - aquasecurity/trivy-action supply chain compromise (critical) — fix in 0.35.0
R1 of the IP-hardening sprint. Verifier now refuses licenses minted for a different host. The mint-time `machine_fp` field is optional — legacy licenses without it stay valid (backwards compat). - app/licensing/fingerprint.py: 4-component SHA-256 (machine-id, MAC, CPU, hostname) + `python -m app.licensing.fingerprint --print` CLI. - generator.generate_license(machine_fp=...) embeds the FP; legacy calls strip the null field so existing tokens stay byte-identical. - verifier.verify_license() compares payload.machine_fp to the live FP; mismatch → HTTPException(403, "license_machine_mismatch"). - schemas.LicensePayload gains optional machine_fp: str | None. - scripts/customer_onboard.sh accepts an optional 6th machine_fp arg. 5 new tests (1860/1855 baseline pre-R2). Image rebuild required.
R2 + R3 + R4 of the IP-hardening sprint. App calls license.automatiabcn.com on boot and once per 24h; fails OPEN within a 7-day grace window so an activation-server outage cannot brick paying customers. After 7 days of consecutive failures the cached valid flag flips to False and quota_monitor blocks paid providers. - app/licensing/phone_home.py: activate_online + heartbeat_online + _check_offline_grace. State at /app/data/license_activation.json. ACTIVATION_URL hardcoded — env override would be a tampering vector. - app/licensing/tamper_check.py: boot-time hash check of verifier source. ABS_VERIFIER_HASH unset = dev no-op; mismatch → RuntimeError. - main.py lifespan: tamper check → activate_online once, behind ABS_TEST_MODE / ABS_PHONE_HOME_DISABLED guards. - Dockerfile: ARG/ENV BUILD_HASH so phone_home._read_build_hash() reports the image identity to the activation server (R3). - scripts/build_with_hash.sh: wraps `docker build` with a combined git-short + source-sha256 hash so post-build tampering is detectable. 4 new tests (offline-grace within/expired, first-boot, build hash). 1864/1855 baseline. Image rebuild required.
…ngerprint
R5 of the IP-hardening sprint. Source-readable Python lets a reverse
engineer flip verify_license() to "return {valid: True}" in seconds.
Compiling these modules to .so shared libraries forces them through a
disassembler — order of magnitude harder.
Production-only: gated behind ABS_COMPILE_CYTHON=1 in the Dockerfile
builder stage. Dev environments keep importing the .py files so
tracebacks stay readable and rebuilds stay fast. Compiled .so are
import-compatible with source .py — pytest works either way.
- core/backend/setup.py: cythonize gates verifier.py + fingerprint.py
+ observability/quota_monitor.py. Lists the IP hardening surface in
one place; removing an entry is a deliberate regression that tests
catch.
- Dockerfile builder: COPY setup.py + conditional `python setup.py
build_ext --inplace` step (cleans .c artefacts after).
1 new test (setup-target whitelist). 1865/1855 baseline. R2 sprint
complete: 8 spec-required tests + 2 backwards-compat extras.
- Worker deployed to abs-license-activation.automatiaabs.workers.dev - KV namespace 'abs-license-state' (id 58aec9f5ab714a2ba3ee2be9b7357ede) - 4 endpoints: /v1/activate, /v1/heartbeat, /v1/admin/revoke, /v1/admin/list-active - Tamper detection: per-jti build_hash drift tracking - Watermark: SHA256(jti:machine_fp:salt) sliced to 16 chars - Admin gate: SHA256-hashed bearer token (founder keeps plaintext offline) phone_home.py URLs updated from license.automatiabcn.com placeholder to the live deployment. When automatiabcn.com migrates to Cloudflare zone, swap to custom domain — Worker route handles both.
Customer-facing compose pulls pre-built images from ghcr.io with no build context, so customers never see Python or Next.js source. The existing infra/docker-compose.yml stays untouched for founder dev. customer_onboard.sh swaps the SSH deploy-key + git-clone flow for a fine-grained ghcr.io read-only PAT (founder issues it manually via the GitHub token UI). The onboarding email now describes the docker login + docker compose pull workflow and ships the customer compose alongside the license JWT.
Founder-facing release script that builds + pushes abs-backend and abs-landing to ghcr.io. Refuses to run with a dirty working tree so the BUILD_HASH baked into the image always corresponds to a real git commit (otherwise customers' phone-home would mark the image tampered without recourse). Bakes BUILD_HASH=<git-short>-<source-sha256> via build args, applies OCI labels, tags v<version>, and idempotently flips the GHCR packages to private visibility. Backend build runs with ABS_COMPILE_CYTHON=1 so verifier / fingerprint / quota_monitor land as .so only.
Production runtime stage now copies app/ from the post-Cython builder instead of the host context, and the builder removes verifier.py / fingerprint.py / quota_monitor.py source after build_ext --inplace when ABS_COMPILE_CYTHON=1. The shipped image contains only the .so shared libraries for those modules — flipping verify_license to "return True" now requires a disassembler instead of a text editor. Adds the abs.build.hash OCI label so the activation server can match the image at phone-home time, and a 5-test regression suite covering the customer compose, release.sh clean-tree gate, Dockerfile source strip, build-hash label, and onboarding email ghcr.io workflow. pytest 1865 → 1870 (+5).
R3 multi-stage Dockerfile strips wget from production image; previous wget healthcheck was reporting unhealthy on every customer deployment even though backend/landing were serving 200. Switch to: - backend: python urllib.request stdlib probe (already in base image) - landing: node http stdlib probe (Next.js standalone uses node 20) Tested locally: both containers report healthy within 60s of boot. Customer-facing — was a release blocker for image-only distribution.
Worker handleAdminList previously returned all activation:* KV entries regardless of revoke state. Two test JTIs (smoke-001 + 2f18...) had been revoked but still surfaced as 'active' in /v1/admin/list-active output. Now we look up revoked:<jti> for each record and drop revoked entries before counting. count + records reflect truly active customers only. Deployed via Wrangler API (etag 050a5d9f). Verified: count=0 post-deploy.
Founder workstation is Apple Silicon (M4); without --platform the buildx default is the local arch (linux/arm64), and customers running on x86_64 hosts (Hetzner CX22 pilot, generic VPS) get "no matching manifest for linux/amd64 in the manifest list entries" when they docker pull, with no obvious diagnostic. Pin PLATFORMS=linux/amd64 by default; honor RELEASE_PLATFORMS env override for the multi-arch (linux/amd64,linux/arm64) case once we add ARM customers. First 1.0.0-rc1 push from this workstation built arm64-only and was caught during the GHCR push step (failed on token scope, masking the platform issue) — fix lands before retry so we do not have to rebuild.
The pilot Round 1 deploy on Hetzner CX22 needed a per-customer Caddy site
address (not the dev-tree's hardcoded "abs.local"). Add a sibling template
infra/Caddyfile.customer that takes ABS_PUBLIC_HOSTNAME from the customer
.env via Caddy's native {$ENV} interpolation, and wire env_file: .env into
the caddy service so the value reaches the container.
Pilot proved the round-trip: Caddy auto-issued a Let's Encrypt cert for
sslip.io subdomain via HTTP-01 in under 5 seconds, HTTP→HTTPS 308 redirect
+ h2/h3 alt-svc working out of the box. Real customers map their own
DNS and set ABS_PUBLIC_HOSTNAME accordingly.
Round 5 found tamper_check silently disabled in production: _verifier_path returned verifier.py while the Cython build strips it, and ABS_VERIFIER_HASH was never set anywhere in the build chain. The Dockerfile builder stage now hashes the produced .so and writes /etc/abs.verifier.hash; tamper_check reads that file as the primary gate (env var stays as dev fallback). Round 3 found _check_offline_grace bypassable via clock rollback: a future last_check yields negative age and grace stays valid forever. _persist_ activation_state now stores monotonic_anchor_ns + activation_age_secs; _check_offline_grace combines wall-clock and monotonic ages (max), and rejects negative wall-clock age outright as offline_grace_clock_drift. Backend regression: 1864 passed (+6 new), 22 env-specific fails unchanged. Six new unit tests in tests/test_p1_*.py lock the patches in place. Closes: GAP-R5-01, VULN-R3-02
…idempotency
ABS Stripe webhook handler needed a persistent dedup store so Stripe retries
do not produce duplicate emails / revoke calls. Two options were on the table:
- Resume Supabase free tier (auto-pauses after 7 days inactivity, painful
for low-traffic webhooks)
- Reuse the existing CF Worker KV (always-on, free tier covers 100x our
expected volume, single source of truth alongside license activation)
Picked the Worker KV. New endpoints:
GET /v1/stripe-event/check?event_id=evt_xxx -> {processed, exists, status, ...}
POST /v1/stripe-event/mark body {event_id, event_type, status[, error]}
Both reuse the existing checkAdminAuth(); web handler authenticates with the
ABS_CF_ADMIN_TOKEN that is already provisioned in the Vercel project env.
KV key format: stripe_event:<event_id>, expirationTtl 30 days (Stripe retry
window is 3 days, 30 gives ample margin for delayed reconciliation runs).
Live-deployed via Wrangler API; 10-case live verification (auth probe,
exists/processed transitions, invalid_status / missing_event_id 400 paths)
all green before this commit.
Replaces the 4-item hardcoded SAMPLE_PROMPTS opener with a 48-prompt library — 8 categories (founder, agency, sales, support, developer, content, finance, data) × 6 prompts × 3 languages (TR/EN/ES). Drawer mounts to the right of MetaSidebar; users open it from the chat sidebar footer or the empty-state CTA, search across all 3 fields, expand a category, and click to fill the message input. Empty state now hydrates 8 hero prompts (one per category, picked via HERO_PROMPT_IDS), localised via EMPTY_STATE_COPY[lang]. ChatClient reads `abs_pref_lang` from localStorage; default `en`. Prompt content delegated to qwen32b/gptoss/kimi (free models); 432 strings, 0 empty. Data-integrity vitest covers every (id, lang, field) triplet. Five new tests in tests/PromptLibrary.test.tsx; the existing ChatSamplePrompts.test.tsx is rewritten to assert the library hydration invariants. Tests: 136 → 141 (+5). Build clean, /panel/chat 1.89 kB.
- scripts/mint_and_email.sh: founder one-command. Wraps customer_onboard.sh, sends bilingual EN+TR HTML via Resend API. Tier sugar (self-host / team-5 / team-10 / maintenance) maps to the underlying tier+seats+days args. --dry-run skips the POST. Resolves the Resend key from env, ~/.config/automatia/, or ai-pc:~/keys. - infra/docker-compose.customer.yml: every service, volume, port and env var now carries an inline YAML comment so the customer can read the file without the runbook. - Customer dry-run on a fresh /tmp host caught BUG-DR1: the compose header advertised ABS_LICENSE_JWT but app/config.py maps the license to ABS_LICENSE_KEY (env_prefix=ABS_), so the backend silently fell back to the bundled trial demo JWT. Renamed to ABS_LICENSE_KEY in the compose header and the email body; second boot produced license_phone_home valid=True and the JTI registered against the Cloudflare activation worker. Pytest: 1876 passed, 10 skipped, 3 deselected, 0 fail, 0 error (ignores: test_providers, test_q03_real_saas_backends, test_update_channel).
…ry-run #2 - .env.example: replace monorepo-developer pointer with customer-facing template (5 required: ABS_LICENSE_KEY, ABS_PUBLIC_HOSTNAME, ABS_PUBLIC_URL, ABS_ACME_EMAIL, ABS_VAULT_KEY; 6 provider keys; pinned ABS_VERSION=1.0.0-rc2; 5 commented optionals). One-line comment at the top redirects developers to core/backend/.env.example + core/landing/.env.example. - main FF'd 253 commits ed55d16 -> 2e20416 (= feat/sprint-q12-deep-quality HEAD). origin/main created (didn't exist). Default branch flipped from feat/sprint-q12-deep-quality to main on enzoemir1/abs in prep for the founder-driven public flip. - Customer install dry-run #2 (/tmp/abs-customer-dryrun-2): boot 43s, ~345 MiB RSS at idle, /healthz 200 internal + via Caddy + HTTPS direct, license_phone_home valid=True, CF Worker activation registered jti 2d7a1aa4..., teardown + revoke clean. Three P1 UX gaps logged for follow-up (multi-arch publish, env_file path, Caddyfile copy step). - Pytest 1882 passed (brief baseline 1864, +18 from recent commits). Two pre-existing env failures unrelated to this sprint: test_marketplace_hardening (order-flake; passes in isolation) and test_watchdog_benchmark (psutil missing in test venv). 0 regressions. Hassas dosya audit: 0 leaked secrets, customer-keys/ ignored, Dockerfile .py strip verified for verifier/fingerprint/quota_monitor when ABS_COMPILE_CYTHON=1. Full report: _agent-tasks/PILOT_TEST_RESULTS_2026-05-08/12_faz_c_go/result.md
Adds the post-push details: commit SHA 415100a, the surfaced automatiabcn/abs public-default-main remote message (founder's parallel flip landed during this sprint), local remote points at enzoemir1/abs which redirects, and the worker exit-criteria checklist.
…in heuristic Two code paths derived a tenant from the email domain (admin@demo-acme.com → "demo-acme"): the login mint (auth._lookup_tenant_slug) and the admin resolver (marketplace._resolve_admin_tenant). The runtime RAG/cascade path (_resolve_tenant) has no such heuristic and falls back to "default" — so a bootstrap admin's admin-managed entities (provider keys, projects, settings, marketplace installs) were stored under a heuristic tenant while the cascade + RAG looked them up under "default". BYOK / project scoping silently broke. Remove the heuristic from both derivation points; a real tenant now comes only from the JWT claim, the users table, or admin_credentials.json — otherwise "default", identical to the runtime resolver. Updated the one test that asserted the heuristic to assert the unified "default" behavior. Only the bootstrap (no explicit tenant) case changes — users with a row keep their tenant. 2463 backend tests pass.
fix(multitenant): unify tenant resolution (drop divergent email-domain heuristic)
) The Workflow Builder could design a workflow but not actually run one, and synthesize always fell back to the 'load sample' CTA: - Builder page renders WorkflowChatPanel without onDryRun, so 'Kuru çalıştır' was a no-op and there was no way to run a saved/built workflow. - defaultSynthesize cast the whole SynthesizeResponse envelope ({workflow, explanation, warnings, ...}) as the WorkflowDefinition, so isValidWorkflow always failed on a real backend response and showed the örnek-şablon CTA. Tests passed only because they inject synthesizeFn and bypass this path. Changes (frontend only, backend contract unchanged): - Unwrap .workflow from the synthesize response. - Dry-run now calls POST /v1/workflows/execute (dry_run=true) when no onDryRun prop is supplied, showing the planned steps + time + USD estimate. - New 'Çalıştır' button enqueues a real run and polls /v1/workflows/jobs/{id} for live state, rendering per-node outputs and engine warnings. - HITL gates surface Onayla/Reddet buttons posting to .../resume. - Run-result panel reflects queued/running/awaiting_approval/done/error. - Keep the existing onDryRun contract for embeds/tests. - Tests: lock in envelope unwrap + run-button + backend dry-run; bump the error-banner intent to >=10 chars to match the synthesize min-length guard.
…ader (#50) The Workflow Builder's Çalıştır / Kuru çalıştır / Kaydet buttons were permanently disabled for everyone: the page derived isAdmin from the `x-abs-role` request header, which nothing ever populated (middleware only validates the session; no layer injects a role). So isAdmin was always false and the action buttons stayed greyed out even for a logged-in admin — synthesize still worked because it isn't admin-gated. Fix: resolve admin status server-side the same way the marketplace page already does — call /auth/me with the session cookie; an authenticated panel user defaults to admin unless /auth/me explicitly returns a non-admin role (it currently returns no role field, so any authenticated user is admin). Fail-closed to false on error / missing cookie.
…s from the panel (#53) A tenant can register a third-party MCP server (GitHub / Slack / their own) from the admin panel; the product connects to it as an MCP *client*, discovers its tools, and (when enabled) re-exposes them through its own /mcp transport so a connected MCP client (e.g. Codex) sees them as ext_<slug>__<tool>. Backend - ExternalMcpServer model (tenant-scoped, Fernet-encrypted auth, RLS) + alembic 0020 (chains off 0018; SQLite no-ops RLS, table via create_all) - app/mcp/external/client.py — outbound streamable-http/SSE client with an SSRF guard (blocks private/loopback/link-local/metadata IPs, http/https only), per-call timeout, response-size cap, tool-description sanitisation - service.py — tenant-scoped CRUD (secret never returned) + test_connection - federation.py — runtime add_tool proxy into the shared FastMCP server, gated behind external_mcp_federate_to_mcp (single-tenant safe); the proxy re-resolves the encrypted secret at call time so rotation takes effect and the token never lingers in the long-lived tool - /v1/admin/external-mcp CRUD + test + federation status, admin-gated, behind external_mcp_enabled (default off) - 21 unit tests (SSRF, encrypted-at-rest, CRUD, tenant isolation, flag gate, federation register/unregister, sanitisation) Frontend - /admin/mcp-servers panel (add / test / enable / remove, discovered-tool chips, "published to /mcp" indicator) + sidebar entry Also corrects a stale PanelSidebar redirect test that the /admin/meetings redirect-loop fix left out of date.
Stage A connector arm · F real metrics · D interactive workflow (+Dry-run) · E approval→action (consent-gated). Alembic heads unified + SQLite column reconciler (deploy-safe). digisfer CD: deploy_digisfer.sh + Jenkinsfile + workflow (images build on-box, port 22 closed). Postgres lane fixes: saved_workflow migration + RLS default-grant. SQLite suite 2569 green; Postgres lane green.
…eat(panel): RAG doc lifecycle Self-serve provisioning (MT Faz0 #3): claiming a public self-signup now bootstraps a real workspace — Tenant + default Project + owner membership — instead of leaving the session pointed at a tenant that does not exist. Idempotent get-or-create; calling it for the single-tenant "default" only makes the canonical rows exist (additive, no regression). ABS_MULTI_TENANT_STRICT (default OFF) closes two fail-open paths that are harmless on single-tenant self-host but would leak across tenants on a shared SaaS instance: - marketplace install/uninstall/list forces the principal's own resolved tenant, so a claim-less admin can no longer act under an arbitrary `tenant=` value; - the raw graph /cypher + /nl-query surface is refused — a scalar/aliased projection (RETURN n.email AS e) carries no tenant_id key and slips past the row filter; the templated graph endpoints stay open. Single-tenant behaviour is byte-identical with the flag off. RAG Knowledge Center (mockup 06): Doküman Lifecycle table — type / version / status / indexed-chunk count / chunk-quality, all derived from real corpus data (oversized chunks are flagged for re-ingestion). Tests: +test_multi_tenant_strict, +test_self_serve_provisioning; full backend suite 2579 passed / 0 failed, frontend vitest 182, tsc clean.
…pt overflow Four correctness fixes surfaced by an end-to-end + adversarial verification pass. 1. fix(chat): a max-length chat message (8000 chars) plus RAG grounding context overflowed CascadeRequest's 8000-char prompt cap, raising an unhandled pydantic ValidationError → HTTP 500. The chat augments the user message (≤8000) with a grounding preamble + retrieved context before the cascade, so the combined prompt legitimately exceeds the user-facing limit. The CascadeRequest copy only feeds the mock helper; clamp it to 8000 while the real orchestrator call still receives the full augmented prompt. (Production impact: any long chat on a corpus-loaded deployment returned 500.) 2. fix(rag): deleting a RAG document only purged its Qdrant chunks, leaving its GraphRAG knowledge-graph nodes (GraphChunk + GraphEntity) orphaned in Neo4j — they would surface in graph-rag answers and bloat the graph. Delete now also purges the doc's graph (flag-gated, best-effort, only when chunks were removed). Made the route async so the purge can await the module-singleton Neo4j driver on its bound loop; the sync Qdrant delete runs in a worker thread. 3. fix(rag): the documents-list and delete endpoints ignored X-Project-Id while the query path honoured it, so a project workspace could see and delete a sibling project's documents. Both now scope by project (same Qdrant filter as query); no header still means tenant-wide. Tests: +regression lock for the chat overflow + project-scope/graph-purge locks; full backend suite 2585 passed / 0 failed (deterministic — this also removes a flake the overflow bug was causing under suite ordering). Follow-up (narrow): graph purge is keyed by tenant+doc_id, not project — a doc ingested under two projects shares one graph; project-scoped purge needs GraphChunk project tagging.
…0260610 Multi-tenant provisioning + strict isolation + RAG/chat correctness fixes
deploy_digisfer.sh died mid-extract with 'no space left on device' while re-pulling the ollama (~3.4G) + whisperx (~2.5G) images: every --build leaves the previous backend image dangling and the box silently filled up. Add a step 3/5 that prunes dangling images + build cache (targeted only — never system/volume prune), prints docker system df, then refuses to rebuild if free space on the docker root (fallback /) is below ABS_MIN_FREE_GB (6 GiB default, ABS_SKIP_DISK_GATE=1 to override). Turns a cryptic mid-build crash into an early, actionable failure.
The deploy fast-forwards /opt/abs to origin/main on the customer box, so every
tracked file ships. Remove material that is internal-only:
- docs/vision.md — internal business strategy (pricing model, ARR targets,
competitor table, TOS open questions). Was published via mkdocs nav; drop the
nav + docs/README entry too.
- artifacts/{cosmos_redesign,sprint_20_impl,sprint_q8} + sprint_q3 audit/phase
logs — internal sprint/audit evidence. Keep promise_verify/ (gated by
test_promise_v6) and sprint_q3/repro.sh (fs-scan allowlist contract).
- benchmarks/results/*.json — stale committed outputs; CI regenerates them.
- founder ops tooling (release/mint/onboard/_mint_license) — untracked from the
repo (kept locally); leaked our release process + key host.
Sanitize residual internal-infra references in shipped files: drop the 'ai-pc'
host mention in the Dockerfile + entrypoint comments, the founder home path in
cost_ledger.json, and a dead artifacts pointer in NeuralGraph.tsx. Harden
.gitignore so these classes never get re-added.
…up-deploy-disk-gate deploy disk-gate + purge internal-only material from customer surface
Follow-up to the vision.md removal. docs-publishing-policy listed strategy, launch/marketing copy, market research and sales playbooks as 'shipped in nav' — but the deploy fast-forwards a customer box, so all of docs/ lands there. Remove the internal go-to-market body and keep only product-technical docs: - docs/research/ (market, competitive analysis, distribution strategy) - docs/launch/ (GA checklist, press kit, copy, A/B, crisis comm) - docs/marketing/, docs/demo/, docs/operations/templates/ (beta), beta-onboarding - docs/first-customer-playbook.md, docs/open-questions.md - docs/qa/bug_report_* + bundle-reports (internal QA evidence) Prune the matching mkdocs nav entries, drop the now-dead first-customer link in index.md, drop the test_first_customer_playbook guard, and rewrite the docs- publishing-policy 'what ships' section to state GTM material is intentionally not shipped.
purge internal GTM/strategy docs from customer surface
…orkflow page The Workflow Designer ran only the graph's agent nodes — retrieval, policy, consent, approval and action nodes were drawn on the canvas but never executed, so a run reported 2 steps while the seed/demo data showed the intended 7. The run also looked inconsistent (real 2-step runs next to 7-step seed rows). Engine: add run_workflow_graph() — traverse every WIRED node topologically and dispatch by kind (agent → Agent Runtime; retrieval → hybrid RAG threaded into the next agent's prompt; policy/consent/approval/action → recorded checkpoints). step_count now mirrors the pipeline on the canvas, so real runs match the seed. The /run endpoint takes the full graph (steps[] still supported for older callers); the Designer now POSTs the graph. ordered_agent_steps refactored onto a shared _topo_order helper. Two regression tests lock it in. Consolidation: there were two confusingly co-named 'Workflow' nav entries. Keep the visual Designer (/admin/workflows); the natural-language builder (/admin/workflow-builder, different node model) loses its duplicate nav entry and redirects to the Designer. Its /v1/workflows/synthesize backend stays for later re-surfacing inside the Designer.
…ne-and-consolidation workflow: execute the full designer graph + one coherent Workflow page
The Designer could ADD nodes but not configure them — the inspector was read-only, so retrieval/policy/consent/approval/action nodes ran on hardcoded defaults and there was no way to author a custom step. (Founder roadmap item a.) - Editable inspector: clicking a node opens a kind-specific config form (retrieval → query/top_k, policy → risk threshold, consent → channel, approval → role, action → type/target). Config persists in the graph and the engine reads it (run_workflow_graph now honours per-node config). - New 'Custom AI step' node: instead of an n8n-style code sandbox (unsafe on a customer box), the operator writes a natural-language instruction that runs on the provider cascade (free-first) with the prior summary + retrieved context threaded in — native to an AI-orchestration product. - Node config flows save → run; nodes added now auto-select so they can be configured immediately. Canvas + palette gain custom_ai/consent styling. - Regression test locks custom_ai cascade execution + config-driven retrieval. Verified: pytest 6/6 (incl new custom_ai+config case); tsc clean; live — adding a Custom AI node opens the editable instruction field.
…d-custom-ai workflow: configurable nodes + natural-language Custom AI step
…er-token revoke MCP tokens are HMAC-stateless (no row at mint), so the panel showed only the last-minted token and could revoke only by pasting a raw string — there was no way to see or manage MULTIPLE active tokens. (Founder roadmap item b.) - New minted_token_record table (alembic 0027): digest-only issuance ledger (label, scope, issued/expiry) — never stores the raw token. - mint records an entry; GET /v1/mcp/tokens lists every issued token (newest first) with a derived status (active | revoked | expired). - Revoke now accepts a token_digest (not just the raw token), so the panel revokes a listed token without re-pasting it; unknown digest → 404. - Panel: 'Üretilmiş token'lar' table — label/scope/issued/expiry/status + a one-click İptal per active token; mint/revoke refresh the list. - Fix: list status guarded against tz-naive (SQLite) vs tz-aware datetime comparison that would 500 the list on a SQLite deployment. Verified: pytest token suite 101 + new multi-token 3 (mint→list→revoke-by-digest) green; OpenAPI revoke-schema contract test updated for the optional token/digest union; tsc clean; live — two tokens listed, one revoked by digest, other intact.
mcp-tokens: manage multiple tokens (ledger + list + per-token revoke)
Setup step 6 ('test') always returned 'skipped — live ping disabled', so a
customer could finish the wizard with bad/typo'd keys and not find out until a
later request failed. (Founder roadmap item d — function-first pass.)
_run_provider_tests now pings each configured provider with the just-entered
key (groq/gemini/cerebras/cohere/anthropic/cloudflare) via the cascade, an 8s
timeout per probe, and records ok/fail. A failed ping is reported but NEVER
blocks completion. Gated by ABS_TEST_MODE (skips real network in tests, so the
8-file setup suite stays deterministic); cf_account_id is marked non-pingable
(Cloudflare is validated via cf_api_token).
Verified: full setup suite 47 passed; new test_setup_provider_ping (ok / fail /
test-mode-skip) 3 passed.
Remaining roadmap-d follow-ups (separate rounds): free-first flow (Anthropic
optional, not a mandatory step 4) + i18n English-default, then the visual
premium pass.
…lidation setup: validate each provider key with a real ping (not 'skipped')
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.29.0 to 7.29.7. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.29.7/packages/babel-core) --- updated-dependencies: - dependency-name: "@babel/core" dependency-version: 7.29.7 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
Contributor
Author
|
OK, I won't notify you again about this release, but will get in touch when a new version is available. If you'd rather skip all updates until the next major or minor version, let me know by commenting If you change your mind, just re-open this PR and I'll resolve any conflicts on it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps @babel/core from 7.29.0 to 7.29.7.
Release notes
Sourced from @babel/core's releases.
... (truncated)
Commits
4fba754v7.29.704ea6b2v7.29.699f498a[7.x packport]Improve input source map handling (#18001)feba0a3Preserve original identifier names from input sourcemaps (#17992) (#17998)Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)You can disable automated security fix PRs for this repo from the Security Alerts page.