feat(skills): rocket-file-browser skill (full scope)#137
Open
afernandez-stratio wants to merge 6 commits into
Open
feat(skills): rocket-file-browser skill (full scope)#137afernandez-stratio wants to merge 6 commits into
afernandez-stratio wants to merge 6 commits into
Conversation
New shared skill that moves files between the Stratio sandbox and Rocket's HDFS File Browser (/rocket/fileBrowser/*), authenticating with the sandbox client certificate over mTLS against Rocket's mutual-TLS listener (port 7777). Calls run with the operating user's own Rocket permissions (no token, no impersonation). Router layout (like cowork-api): minimal SKILL.md + tasks/ + a single Python client scripts/rocket_file_browser.py. MVP scope: - filesystems: GET /fileBrowser/getFilesystems (discover id/type, auto-resolve when only one exists) - download: POST /fileBrowser/download, streamed to a local path - upload: two-phase (POST /fileBrowser/uploadLocalFile then /putLocalFileToHadoopFs) with automatic retry on HTTP 420 Reuses guides/external-api-calls.md for mTLS/env/error conventions; the only delta is ROCKET_API_URL on the mutual-TLS port. Refuses Rocket-restricted roots client-side and surfaces HTTP code + body verbatim on failure. Spanish mirror under es/. Planned extension: ls/cp/mv/rm/mkdir/compress/extract + pytest. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ess/extract)
Extend the MVP (download/upload/filesystems) to the complete File Browser
surface, all through the same Python client:
- ls -> POST /fileBrowser/findByPath
- mkdir -> POST /fileBrowser/createDir
- rm -> DELETE /fileBrowser/delete (one or more paths)
- cp / mv -> PUT /fileBrowser/copy / /fileBrowser/update
- compress -> PUT /fileBrowser/compress (codecs: ZStandard, Lz4, Snappy, Gzip,
Bzip2, Zip [default], TarGz)
- extract -> PUT /fileBrowser/extract
Each op reuses the existing mTLS/filesystem-resolution/restricted-path-guard
helpers and surfaces HTTP code + body verbatim on failure. Added a task file per
operation (EN + es mirror), updated the SKILL.md router index and README, and
added a pytest suite (payload construction, fs auto-resolution, restricted-path
guard, error surfacing, 420 upload-commit retry).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sion End-to-end testing against a live Rocket showed the compress endpoint appends the codec extension to compressedFile (e.g. out.zip -> out.zip.zip), which then breaks extract if the original name is reused. Document the behaviour in the compress task (EN + es) and emit a note from the client so the user knows the real archive name to extract. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…amples ROCKET_API_URL resolves with the short service form https://<rocket-instance>.<rocket-namespace>:7777/rocket (same style genai-api produces for it via discovery, resolved through the pod search domain). Replace the FQDN examples (svc.<cluster-domain>) accordingly in SKILL.md, README and the client docstring/error message (EN + es). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The trailing "/rocket" was mistaken for a fixed path prefix; it was actually the instance name (always "rocket" in the examples). On the mutual listener the client calls /fileBrowser/... directly, so ROCKET_API_URL must be just the host:port, e.g. https://rocket.s000001-rocket:7777 (verified with another instance: https://rocket-dlc.s000001-rocket:7777/fileBrowser/getFilesystems). Update SKILL.md, README and the client docstring/error message (EN + es). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review pass over the whole feature before merge:
- guard_path did a raw string prefix check, so "/data/../backups/x" (and other
"." / ".." / repeated-slash forms) slipped past the restricted-root guard
even though it resolves to a restricted path. Normalize with posixpath.normpath
before comparing. Careful with normpath's POSIX quirk of preserving an exactly
double leading slash verbatim -- lstrip first so re-prepending "/" doesn't
accidentally produce that case.
- Add tests for the traversal forms this fixes, plus legit paths that must
still pass (including a look-alike prefix like /backups-not-really/x).
- Drop a redundant double .strip('"') in the upload docker_path parsing.
- SKILL.md/README (EN+es) still described the endpoint as "/rocket/fileBrowser/*"
in the frontmatter description and opening paragraph -- stale from before the
host:port-no-path fix. Corrected to "/fileBrowser/*".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
afernandez-stratio
force-pushed
the
feature/rocket-file-browser-skill
branch
from
July 11, 2026 20:43
66f9432 to
2573a97
Compare
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.
Qué
Skill compartida
rocket-file-browser: gestiona ficheros en el File Browser HDFS de Rocket (/fileBrowser/*) desde el sandbox de OpenCode, sin el roundtrip manual por la UI.Autenticación e identidad
/vault/secrets/cert.crt, CN = usuario operador, p.ej.s000001-user) contra el listener mutual-TLS de Rocket (puerto 7777).Oauth2Mutual; el ingress público (443) es solo oauth2/cookie e ignora el cert →ROCKET_API_URLapunta al mutual por DNS de servicio interno (host:port, sin path):https://<rocket-instance>.<rocket-namespace>:7777(p.ej.https://rocket.s000001-rocket:7777).s000001.Alcance (completo)
Router (estilo
cowork-api):SKILL.md+tasks/+ cliente Pythonscripts/rocket_file_browser.py.downloadPOST /fileBrowser/download(streaming a disco)uploaduploadLocalFile+putLocalFileToHadoopFs(+ retry HTTP 420)lsPOST /fileBrowser/findByPathcp/mvPUT /fileBrowser/copy//fileBrowser/updatermDELETE /fileBrowser/deletemkdirPOST /fileBrowser/createDircompress/extractPUT /fileBrowser/compress(codecs ZStandard/Lz4/Snappy/Gzip/Bzip2/Zip/TarGz) //fileBrowser/extractfilesystemsGET /fileBrowser/getFilesystems(auto-resuelve si solo hay uno)Rechaza raíces restringidas de Rocket en cliente, muestra HTTP code + body verbatim en error. Espejo español bajo
es/. Testspytestenscripts/test_rocket_file_browser.py.Dependencia
ROCKET_API_URLla inyecta la plataforma en el pod del sandbox — ver Stratio/genai-api#507 y Stratio/genai-agents-sandbox#71.Test plan
Probado end-to-end contra Rocket real (port-forward + certs locales): los 9 endpoints OK —
filesystems,mkdir,upload,ls,cp,mv,compress,extract,download(diff idéntico),rm. Ejemplo:ROCKET_API_URL=https://rocket.s000001-rocket:7777python3 scripts/rocket_file_browser.py filesystems🤖 Generated with Claude Code