Skip to content

Tags: hoophq/hoop

Tags

1.140.4

Toggle 1.140.4's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(rdp): apply connection data masking rules (#1711)

* fix(rdp): apply connection data masking rules
* fix(rdp): validate data masking policy inputs
---------

Co-authored-by: MisterMal <teskeslab@lucasteske.dev>

1.140.3

Toggle 1.140.3's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
DEP-138: move expired-credential session cleanup off the read paths (#…

…1708)

* DEP-138: move expired-credential session cleanup off the read paths

GET /api/sessions opened with models.CloseExpiredCredentialSessions()
before parsing a single query param. That made a read mutate, and the
query it ran was not scoped to the caller's org: a read for one tenant
closed sessions for every tenant on the deployment, as 1+2N serial
statements with no bound on N and every per-row error discarded.

The work now runs in gateway/jobs/credentialsweeper, a 15s ticker
started from main.go, and the model function is a single set-based
statement: FOR UPDATE SKIP LOCKED so replicas take disjoint slices, and
a LIMIT so a backlog drains over several ticks instead of in one long
transaction that pins the xmin horizon. Migration 000109 adds a partial
index matching the sweep predicate.

Removed from all four call sites. The two credential handlers lose
nothing: CreateConnectionCredentials already closes the prior session
in issueOrRefreshCredential, and ResumeConnectionCredentials' 410 gate
is backstopped by its own expire_at check. On the GETs the only delta
is timing — a session reports done within 15s of expiry rather than
whenever anyone next hit one of those endpoints.

* fix: Sweeper runs uncancelled

* chore: renumber the credential sweep index migration to 000110

1.140.2

Toggle 1.140.2's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(rdp): bound onnxruntime threads in the OCR sidecar (+ benchmark t…

…ooling) (#1658)

* fix(rdp): bound onnxruntime thread pools in the OCR sidecar

Left at ONNX Runtime's default, every InferenceSession sizes its intra-op
thread pool to the host's logical core count. The sidecar creates many
sessions per uvicorn worker — the RapidOCR engine (det/rec/cls) plus one
fixed-shape session per recognition and detection bucket, ~19 in total —
and runs WEB_CONCURRENCY workers. That product is fine on a small node but
explodes on a high-core host: on a 192-core GPU box it demands tens of
thousands of threads and the sidecar dies during warmup with
"pthread_create failed, error code: 11" before serving a single request.

Bound both pools and apply them at every session the server creates: the
engine (via EngineConfig.onnxruntime.*), the per-bucket detection sessions,
and the fixed-shape fp16 recognition sessions. The GPU does the heavy
compute and serving throughput comes from concurrent workers, not intra-op
parallelism inside one inference, so a small pool is sufficient as well as
necessary. Defaults (intra 4 / inter 1) are overridable per deployment via
OCR_INTRA_OP_THREADS / OCR_INTER_OP_THREADS.

Also make the CUDA arena growth strategy configurable in the same config
block (OCR_CUDA_ARENA_STRATEGY, default unchanged at kNextPowerOfTwo).
The default rounds each arena up to a power of two, which inflates
per-worker VRAM (~4.8GB on an 80GB card) and limits how many workers fit;
kSameAsRequested trades allocation frequency for a smaller footprint on
VRAM-constrained GPUs. It shares the session-construction paths touched
above, so it is not separable into its own commit.

 🤖 Generated with Mister Maluco

Co-Authored-By: MisterMal <teskeslab@lucasteske.dev>

* feat(rdpbench): add -concurrency and -compare-url to ocrbench

ocrbench could only drive the OCR server serially, which measures
per-request latency but not what the gateway analyzer actually does: it
issues up to 8 concurrent chunk requests, so sustained throughput under
concurrency is the number that decides capacity.

-concurrency N dispatches the sampled band states across N workers and
reports aggregate throughput at that level. Band extraction stays serial
(compositing mutates a shared framebuffer in event order); each band is
copied out so the parallel phase reads immutable buffers, and the latency
stats are mutex-guarded.

-compare-url cross-checks a second OCR server against the first and
reports tokens the primary DROPPED relative to the reference, flagging
PII-shaped ones (>=4 digits or '@') separately from UI-chrome noise. Word
order and whitespace are ignored — a token-based PII scan does not care,
but a lost token is a potential leak. This is what verified an fp16
recognition runtime does not lose PII that fp32 catches.

 🤖 Generated with Mister Maluco

Co-Authored-By: MisterMal <teskeslab@lucasteske.dev>

* chore(rdp): add aarch64/CUDA13 OCR sidecar image for Blackwell (sm_121)

Dockerfile.rapidocr-gpu-aarch64 builds the OCR PoC sidecar for aarch64 +
CUDA 13 + GB10 (Grace-Blackwell, sm_121) — the DGX Spark. It is a separate
file rather than a base-image swap because the x86 GPU image is
fundamentally incompatible with that platform:

  - No aarch64 + CUDA 13 onnxruntime-gpu wheel is published on PyPI, so the
    wheel must be built from source for this arch.
  - The ORT 1.20 line the x86 images pin does not compile against CUDA 13
    at all (CCCL removed thrust::unary_function); GB10 needs >= 1.24.4, so
    this image cannot reuse that pin.
  - GB10 is compute capability 12.1, so the build needs
    CMAKE_CUDA_ARCHITECTURES=121 — a stock sm_80/86/90 wheel lacks the
    kernel images and silently falls back to CPU.

Because it installs a source-built wheel rather than resolving
onnxruntime-gpu from PyPI, this image is unaffected by the 1.20.1 yank
handled in #1657. The header documents producing the wheel. CUDA 13 +
cuDNN 9 come from the base image, so unlike the x86 file there are no
explicit nvidia-*-cu12 pins. fp16 recognition models are converted at
build time, mirroring Dockerfile.agent-ocr-gpu.

 🤖 Generated with Mister Maluco

Co-Authored-By: MisterMal <teskeslab@lucasteske.dev>

* chore: ignore bare cmd binaries dropped in the repo root

`go build ./gateway/cmd/rdpbench/` (without -o) writes the binary to the
current directory, so a routine build from the repo root leaves a ~44MB
executable sitting next to the source — easy to stage by accident.

Ignore the four root-level names our main packages produce. They are listed
explicitly rather than matched by pattern because such a pattern would be
indiscriminate: ./gateway is deliberately absent, since ignoring it would
shadow the gateway module directory. (That build is harmless anyway — Go
refuses to overwrite an existing directory.)

 🤖 Generated with Mister Maluco

Co-Authored-By: MisterMal <teskeslab@lucasteske.dev>

* fix(rdpbench): keep '@' through token normalization in compare mode

normalizeToken stripped every non-alphanumeric character, so "a@b.com" and
"ab.com" both normalized to "abcom". A candidate engine that dropped the
'@' out of an email therefore compared equal to the reference, was never
reported as a dropped token, and never reached the PII-shaped classifier —
silently missing exactly the kind of loss the cross-check exists to catch.

The underlying invariant is that any character the classifier keys on must
survive normalization. Express it directly: piiMarkerRune now defines that
set, normalizeToken preserves it alongside alphanumerics, and the classifier
tests membership with the same predicate instead of its own literal '@', so
the two cannot drift apart.

Adds ocrbench_test.go covering normalizeToken (case, separator punctuation,
digits, empty/non-ascii) and droppedTokens (multiset semantics, order and
whitespace insensitivity, reporting in original form), including a
regression case for the email above and a guard asserting no marker rune is
ever stripped.

Also route both /healthz probes through a probeHealth helper that surfaces
read errors, rather than discarding them and benchmarking on against a
banner that silently came back empty.

 🤖 Generated with Mister Maluco

Co-Authored-By: MisterMal <teskeslab@lucasteske.dev>

* fix(rdp): apply the CUDA arena strategy to the engine's sessions too

OCR_CUDA_ARENA_STRATEGY was documented as covering every session's GPU
memory pool but was only passed to the manually built bucket det/rec
sessions. The RapidOCR engine constructs its own det/rec/cls CUDA sessions,
which kept the built-in default, making the knob quietly partial: it
changed the bucket sessions' footprint but not the engine's.

rapidocr exposes the setting at EngineConfig.onnxruntime.cuda_ep_cfg
.arena_extend_strategy, so plumb it there rather than weakening the
documented contract. The engine's sessions hold VRAM even in fp16 mode —
where BucketDet/BucketRec serve the actual inferences — so they count
toward the per-worker footprint the knob exists to control.

Document the new runtime knobs where the sidecar's others already live:
the Dockerfile.agent-ocr-gpu env reference block and the gcp-gpu-agent
env sample. They are consumed by the OCR container, not the gateway, so
they do not belong in the root .env.sample (which carries only the
gateway-side RDP_OCR_SERVER_URL).

 🤖 Generated with Mister Maluco

Co-Authored-By: MisterMal <teskeslab@lucasteske.dev>

* chore: never commit rdpbench framebuffer snapshots

`rdpbench run -dump <dir>` writes each analyzed frame to
snapshot-NNNN.png — full-canvas decodes of the recorded RDP session, i.e.
the same sensitive screen content .gitignore already refuses to accept in
/recording.json, except directly viewable rather than encoded in a fixture.
Only the fixture was protected, so a dump left in the tree could be picked
up by a wide `git add`.

The dump directory is supplied by the caller and can be created anywhere in
the repo, so match the tool's own filename rather than guessing directory
names. Verified the pattern catches dumps at the root and nested, and does
not shadow the tracked README assets (backedby.png, github.png).

 🤖 Generated with Mister Maluco

Co-Authored-By: MisterMal <teskeslab@lucasteske.dev>

---------

Co-authored-by: MisterMal <teskeslab@lucasteske.dev>

1.140.1

Toggle 1.140.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
ENHANCE: shows open connections first always on native connections dr…

…awer (#1707)

* shows open connections first always on native connections drawer

* fix duplication on expiration issue

1.140.0

Toggle 1.140.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
chore(deps): alcatraz v0.16.0 for the Brazilian identifiers (#1700)

The six recognizers this branch carried locally -- CNS, título
eleitoral, RENAVAM, CEP, plate and PIX key -- are upstream as of
hoophq/alcatraz#29, so the local copy goes and the pin moves v0.7.0 ->
v0.16.0.

Upstream also owns the checksum helpers the local copy had duplicated,
and picked up two fixes from review there: the PIX gate no longer
accepts a bare "chave" (Portuguese for "key", which matched ordinary
primary-key columns), and both context-gated patterns score above a
realistic caller threshold instead of being dropped despite their gate
passing.

Verified on the bumped module: 54 entity types, all six BR types
detected, and the false-positive guards hold -- "chave primaria <uuid>"
and a plain eight-digit order id stay unmasked.

 Generated with Mister Maluco

Co-authored-by: MisterMal <teskeslab@lucasteske.dev>

1.139.0

Toggle 1.139.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(hoopinspect): defer rule verdicts to OPA, rewrite the SQL scanner (

#1704)

* add: lexer sql for improvements and make the ai session analyzer use opa

* docs: improvements

* fix some docs

* SQL server support on hoop proxy (17,19,22, latest...) (#1705)

* add: mssql encrypt_off flag for tls

* add: fix docs

* add: fix docs

* add: mssql 2019 support and run envoy stack overy 2017, 2019, 2022 and latest

* add: fix operations hoopinspector

1.138.2

Toggle 1.138.2's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(mcp): add tag_selector filter to connections_list so tags are fil…

…terable (#1706)

* add: fix(mcp): filter connections_list by tag_selector instead of legacy tags array

* fix(mcp): add tag_selector filter to connections_list, deprecate legacy tags

* fix(models): keep every tag_selector constraint and tolerate blank segments

1.138.1

Toggle 1.138.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix: bound terminal output rendering and handle draft quota (EVL-121) (

…#1703)

* fix(webclient): bound terminal output rendering and handle draft quota (EVL-121)

The web terminal froze on large command output. The gateway returns up to
sessionwal.DefaultMaxRead (110MB) and the log area rendered all of it into a
single unvirtualized `whitespace-pre` node, producing an element wide enough
to exceed browser layout limits: blank viewport, multi-million-pixel scroll
width and a pinned main thread on any scroll.

Reproduced by holding the input constant and varying only the output. The
same 15,728,646-byte input against `bash -c 'wc -c'` (small output) renders
fine; against plain `bash`, which echoes the payload back as "command not
found" on stderr, it froze the tab. Output size is independent of input size,
so an input cap does not address this.

- log_area/logs.cljs: cap what reaches the DOM at 512KB and surface a callout
  pointing at the output menu, which already routes payloads above its own
  threshold to the backend download flow. The untruncated string stays in the
  app db, so downloads and copy are unaffected. The screen reader label now
  derives from the bounded string instead of running split-lines over the
  whole payload on every render.
- log_area/main.cljs: only run papaparse + js->clj when the connection type
  can actually surface the Tabular tab or the CSV/JSON downloads that consume
  the matrix. Non-database connections were paying a full-payload scan on
  every render for a result nothing reads.
- panel.cljs: catch the QuotaExceededError that localStorage raises above
  ~5MB. The uncaught throw skipped the status reset and left the footer
  spinner running forever, reading as a hang. Adds a :not-saved state that
  says so, and warns that a reload restores the previous draft, since setItem
  is atomic and the stale value survives a rejected write.

* fix(webclient): lower output render cap to 512KB (EVL-121)

Interactive testing showed 1MB still degrades scroll on the pathological
single-unwrapped-line shape. Layout is only half the cost — repaint of a
very wide node slows down well before Chrome's 2^25 clamp, which the
headless layout benchmark does not capture. 512KB stays responsive.

* style(webclient): make output truncation callout full width (EVL-121)

1.138.0

Toggle 1.138.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
EVL-185: onboarding signup origin survey (#1701)

Adds the onboarding "How did you hear about Hoop?" survey: two nullable columns on private.users, POST /users/self/signup-origin with a first-answer-wins conditional update, show_origin_survey on /userinfo derived from users.created_at, and a floating survey widget in webapp_v2. The answer is also emitted to Segment as hoop-onboarding-origin-answered, without the free text.

1.137.1

Toggle 1.137.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(sec): bump grpc lib to latest version to fix GHSA-hrxh-6v49-42gf (#…

…1697)

* go mod tidy to all packages