Pin panel versions, report runtime status, fix log preconditions - #6
Conversation
The panel API is the whole contract here, and it moves between releases. Two things were missing: a single place listing the routes this project calls, and any signal when the panel in front of us is outside the range those routes were verified against. Route surfaces are now extracted from the official easypanel/easypanel images and pinned per release in testdata. Across 2.32.2, 2.33.0 and 2.33.1 the panel exposes the same 375 procedures with identical input fields, which is why one code path covers 2.32.0..2.33.1. - internal/easypanel/routes.go declares every route, replacing scattered string literals; RequiredRoutes drives the compatibility test. - Tests assert each route exists in every pinned release and that its input shape is unchanged across them. - Client.PanelVersion reads info.version from /api/openapi.json, the one version route present in all supported releases (/api/cli.json is 2.33+ only). - grpc-server logs the panel version and support state at startup; EASYPANEL_SKIP_VERSION_CHECK=1 skips the probe. - New CLI commands: settings panel-version, settings logs. - scripts/panel-surface.sh re-pins surfaces after a panel upgrade.
Three gaps showed up while checking every RPC against a live panel. GetLogs returned the panel's opaque "[BAD_REQUEST] fetch failed". Easypanel serves logs only from its own Loki deployment (queryServiceLogs fetches LOKI_URL/loki/api/v1/query_range) and exposes no docker-logs route at all. Loki and Promtail exist only when log aggregation is enabled, a licensed feature. The RPC now prechecks logs.getSettings and returns FailedPrecondition naming the cause and the fix, and separately reports an enabled-but-unreachable log store. It also forwards the panel's remaining filters (stream, levels, search, start, end), clamps limit to the panel maximum of 1000 instead of tripping validation, and rejects bad stream values locally. GetServiceStatus returned stored configuration only, so a compose service came back with no image and no indication of whether it was running. It now merges the panel's Docker view: status (running/stopped/unknown), running_containers, containers[], and compose_services[] for compose. A refused container query degrades to unknown rather than failing the call. BREAKING: GetServiceStatus no longer returns env values by default. The panel stores secrets in the same env blob its inspect routes return, and a GRPC_AUTH_TOKENS entry can read every project, so keys are kept and values become <redacted>. Set include_env on the request for clear text.
- CHANGELOG.md with the v0.1.0 entry, including the GetServiceStatus env behaviour change and the supported Easypanel range. - README: supported panel versions and how to re-pin them, service status fields, env redaction, log requirements, unit vs live test commands, 0.1.0 image tags. - Deployment guide: status/runtime fields, include_env, log filters and the licensed-Loki requirement, panel-version troubleshooting, 0.1.0 examples. - .env.example: EASYPANEL_SKIP_VERSION_CHECK.
|
Warning Review limit reached
Next review available in: 32 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (15)
📝 WalkthroughWalkthroughThe change adds Easypanel route-surface validation, panel version and log probes, runtime container status, environment redaction, filtered logs, CLI commands, release documentation, and unit and end-to-end tests. ChangesPanel compatibility and runtime observability
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant GRPCClient
participant PaaSServer
participant Easypanel
participant Docker
GRPCClient->>PaaSServer: Request runtime status or logs
PaaSServer->>Easypanel: Query service or log data
PaaSServer->>Docker: Query container runtime data
Docker-->>PaaSServer: Return container details
Easypanel-->>PaaSServer: Return panel data
PaaSServer-->>GRPCClient: Return status, redacted environment, or logs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (8)
internal/easypanel/routes.go (1)
25-26: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueFix the stale identifier in the comment.
The comment names
appOnlyProcedures, but the variable at Line 66 istypeOnlyProcedures.📝 Proposed fix
// Per-type procedure names. Not every service router exposes all of them; -// appOnlyProcedures records the ones that only exist under services.app. +// typeOnlyProcedures records the ones that exist under a single service router.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/easypanel/routes.go` around lines 25 - 26, Update the comment describing the per-type procedure names to reference typeOnlyProcedures instead of the stale appOnlyProcedures identifier, matching the variable declared near the router definitions.scripts/extract-panel-surface.py (2)
11-12: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueClose the file handles.
loadandjson.dumpleave file objects open until garbage collection. Usewithblocks. Also validatesys.argvlength so a missing argument reports usage instead ofIndexError.♻️ Proposed refactor
def load(path): - return open(path, encoding="utf8", errors="replace").read() + with open(path, encoding="utf8", errors="replace") as fh: + return fh.read()- json.dump(out, open(sys.argv[2], "w"), indent=1, sort_keys=True) + with open(sys.argv[2], "w", encoding="utf8") as fh: + json.dump(out, fh, indent=1, sort_keys=True)Also applies to: 241-241
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/extract-panel-surface.py` around lines 11 - 12, Update load to open the file through a with block so its handle is closed deterministically, and apply the same context-manager pattern to the json.dump file operation. Add sys.argv length validation before argument access, reporting usage and exiting cleanly when the required path argument is missing.
120-120: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove the unused
SCHEMA_ALIASconstant.No code reads or writes
SCHEMA_ALIAS.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/extract-panel-surface.py` at line 120, Remove the unused SCHEMA_ALIAS constant declaration, ensuring no other code or behavior is changed.scripts/panel-surface.sh (1)
32-36: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winRemove the container if a step fails.
set -eaborts the loop ifdocker export,tar, or the python steps fail. Thedocker rmon Line 36 then never runs, and the created container stays on the host. Register cleanup right afterdocker create.♻️ Proposed refactor
container="ep-surface-${version//./-}-$$" docker create --name "$container" "$IMAGE:$version" >/dev/null + trap 'docker rm -f "$container" >/dev/null 2>&1 || true; rm -rf "$WORK"' EXIT # Only app/backend.js is needed; the rest of the image is ~900MB. docker export "$container" | tar -x -C "$WORK" app/backend.js app/package.json docker rm "$container" >/dev/null🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/panel-surface.sh` around lines 32 - 36, Register cleanup immediately after the docker create command for the container created in the panel-surface extraction flow, so failures in docker export, tar, or subsequent processing still remove it. Ensure cleanup runs on script exit while preserving the existing explicit docker rm behavior without attempting unsafe duplicate removal.internal/easypanel/routes_test.go (1)
130-141: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse
strings.Joinin thejoinhelper.The manual loop repeats standard-library behavior.
sort.Stringsplusstrings.Joinis shorter and avoids repeated string allocation.♻️ Proposed refactor
func join(in []string) string { sorted := append([]string(nil), in...) sort.Strings(sorted) - out := "" - for i, s := range sorted { - if i > 0 { - out += "," - } - out += s - } - return out + return strings.Join(sorted, ",") }Add
"strings"to the import block.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/easypanel/routes_test.go` around lines 130 - 141, Update the join helper to retain the sorted copy from sort.Strings and return strings.Join(sorted, ",") instead of manually concatenating elements; add the strings import required for this standard-library helper.internal/server/getlogs_test.go (1)
16-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a case for the fail-open path of the aggregation precheck.
GetLogsonly rejects the request whenLogAggregationreturns no error. When the settings probe itself fails, the code continues to the query route. No test covers that branch. A test that leaveseasypanel.RouteLogsGetSettingsunstubbed would pin this intentional fail-open behavior.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/server/getlogs_test.go` around lines 16 - 36, Add a test alongside TestGetLogsRejectsDisabledLogAggregation that leaves easypanel.RouteLogsGetSettings unstubbed, invokes GetLogs with the same request, and verifies the settings-probe error does not prevent the query route from being called. Assert the intentional fail-open outcome while keeping the existing disabled-aggregation test unchanged.internal/server/panel_fake_test.go (1)
56-64: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winHonor the status code parsed from the
!<status>prefix.The fixture format documents a status code, but
handlediscardsparts[0]and always writes 400. A future fixture such as!500 {...}would still return 400, and a test that asserts on server-side status mapping would pass for the wrong reason.♻️ Proposed fix
if strings.HasPrefix(resp, "!") { // "!<status> <body>" returns an error response. parts := strings.SplitN(strings.TrimPrefix(resp, "!"), " ", 2) - w.WriteHeader(http.StatusBadRequest) + code, err := strconv.Atoi(parts[0]) + if err != nil { + p.t.Errorf("fake panel: invalid status prefix %q for route %s", parts[0], route) + code = http.StatusBadRequest + } + w.WriteHeader(code) if len(parts) == 2 { _, _ = w.Write([]byte(parts[1])) } return }Add
"strconv"to the imports.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/server/panel_fake_test.go` around lines 56 - 64, The error-response branch in handle must use the status code encoded in parts[0] rather than always returning http.StatusBadRequest. Parse parts[0] with strconv, write the parsed status when valid, and preserve the existing bad-request fallback for malformed or missing status values.internal/server/paas.go (1)
379-381: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winGate
include_envwith an authorization scope before returning clear-text env.
IncludeEnvexposesEnvvalues without any check beyondauth.Interceptor, whileauth.Interceptoronly validates token membership. If these gRPC tokens are shared across callers, consider a dedicated scope or permission for clear-text environment variables, or keep defaults enforced per token type.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/server/paas.go` around lines 379 - 381, Update the response handling around IncludeEnv in the relevant server method so clear-text environment values are returned only when the caller has an explicit authorization scope or permission for environment access. Reuse the existing auth/interceptor authorization model and preserve redactEnvValues as the default for unauthorized or absent permission, rather than relying solely on token membership.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cmd/grpc-server/main.go`:
- Around line 41-46: Update the EASYPANEL_SKIP_VERSION_CHECK condition around
reportPanelVersion so the probe is skipped only when the environment value
equals "1"; run reportPanelVersion for unset, "0", and all other values.
In `@docs/deployment-guide.md`:
- Around line 8-11: Mark the v0.1.0 installation examples as pending until the
release artifacts exist, and update every affected reference to use an available
published tag instead of 0.1.0/v0.1.0. In docs/deployment-guide.md#L8-L11,
docs/deployment-guide.md#L64-L78, docs/deployment-guide.md#L87-L87,
docs/deployment-guide.md#L573-L580, docs/deployment-guide.md#L595-L595, and
docs/deployment-guide.md#L886-L889, adjust the release/image examples
accordingly; in README.md#L504-L510, do the same for the server and CLI image
tags.
In `@internal/easypanel/version.go`:
- Around line 14-22: Align the supported version floor with pinned coverage: in
internal/easypanel/version.go lines 14-22, either set MinSupportedVersion to
2.32.2 or add a 2.32.0 fixture while correcting the surrounding comment; in
scripts/panel-surface.sh lines 18-22, update the default VERSIONS list to start
at the same chosen floor and keep its comment accurate.
- Line 110: Update the deferred response-body cleanup in the surrounding HTTP
request function to explicitly discard the return value from resp.Body.Close,
satisfying errcheck while preserving the existing cleanup behavior.
In `@internal/server/paas.go`:
- Around line 798-803: Update the GetLogs precheck around LogAggregation so a
disabled or unavailable aggregation result invalidates the cached log settings
before returning FailedPrecondition, allowing a retry to observe newly enabled
aggregation without waiting for the TTL. Preserve the existing enabled-settings
path and error response behavior.
In `@README.md`:
- Around line 422-426: Update the fenced code block containing the panel log
aggregation error text to specify the text language identifier, preserving its
existing content.
In `@scripts/extract-panel-surface.py`:
- Around line 2-5: Correct the usage example in the module docstring to use the
actual script name extract-panel-surface.py, matching the filename invoked by
scripts/panel-surface.sh.
---
Nitpick comments:
In `@internal/easypanel/routes_test.go`:
- Around line 130-141: Update the join helper to retain the sorted copy from
sort.Strings and return strings.Join(sorted, ",") instead of manually
concatenating elements; add the strings import required for this
standard-library helper.
In `@internal/easypanel/routes.go`:
- Around line 25-26: Update the comment describing the per-type procedure names
to reference typeOnlyProcedures instead of the stale appOnlyProcedures
identifier, matching the variable declared near the router definitions.
In `@internal/server/getlogs_test.go`:
- Around line 16-36: Add a test alongside
TestGetLogsRejectsDisabledLogAggregation that leaves
easypanel.RouteLogsGetSettings unstubbed, invokes GetLogs with the same request,
and verifies the settings-probe error does not prevent the query route from
being called. Assert the intentional fail-open outcome while keeping the
existing disabled-aggregation test unchanged.
In `@internal/server/paas.go`:
- Around line 379-381: Update the response handling around IncludeEnv in the
relevant server method so clear-text environment values are returned only when
the caller has an explicit authorization scope or permission for environment
access. Reuse the existing auth/interceptor authorization model and preserve
redactEnvValues as the default for unauthorized or absent permission, rather
than relying solely on token membership.
In `@internal/server/panel_fake_test.go`:
- Around line 56-64: The error-response branch in handle must use the status
code encoded in parts[0] rather than always returning http.StatusBadRequest.
Parse parts[0] with strconv, write the parsed status when valid, and preserve
the existing bad-request fallback for malformed or missing status values.
In `@scripts/extract-panel-surface.py`:
- Around line 11-12: Update load to open the file through a with block so its
handle is closed deterministically, and apply the same context-manager pattern
to the json.dump file operation. Add sys.argv length validation before argument
access, reporting usage and exiting cleanly when the required path argument is
missing.
- Line 120: Remove the unused SCHEMA_ALIAS constant declaration, ensuring no
other code or behavior is changed.
In `@scripts/panel-surface.sh`:
- Around line 32-36: Register cleanup immediately after the docker create
command for the container created in the panel-surface extraction flow, so
failures in docker export, tar, or subsequent processing still remove it. Ensure
cleanup runs on script exit while preserving the existing explicit docker rm
behavior without attempting unsafe duplicate removal.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 986bd167-d006-49b6-8909-3c685c1c857b
⛔ Files ignored due to path filters (1)
proto/paas.pb.gois excluded by!**/*.pb.go
📒 Files selected for processing (26)
.env.exampleCHANGELOG.mdREADME.mdcmd/grpc-server/main.gocmd/services.gocmd/settings.godocs/deployment-guide.mdgrpc_e2e_test.gointernal/easypanel/client.gointernal/easypanel/routes.gointernal/easypanel/routes_test.gointernal/easypanel/testdata/panel-surface-2.32.2.jsoninternal/easypanel/testdata/panel-surface-2.33.0.jsoninternal/easypanel/testdata/panel-surface-2.33.1.jsoninternal/easypanel/version.gointernal/easypanel/version_test.gointernal/server/env.gointernal/server/env_test.gointernal/server/getlogs_test.gointernal/server/logs.gointernal/server/paas.gointernal/server/panel_fake_test.gointernal/server/status_test.goproto/paas.protoscripts/extract-panel-surface.pyscripts/panel-surface.sh
| // Probe the panel version so route drift shows up at boot instead of on the | ||
| // first failing RPC. Never fatal: a slow or briefly unreachable panel should | ||
| // not stop the server from serving. | ||
| if os.Getenv("EASYPANEL_SKIP_VERSION_CHECK") == "" { | ||
| reportPanelVersion(ep, endpoint) | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Only skip the version probe when the value is 1.
EASYPANEL_SKIP_VERSION_CHECK=0 currently skips the probe. This conflicts with the documented =1 contract and can hide an unsupported panel version.
Proposed fix
- if os.Getenv("EASYPANEL_SKIP_VERSION_CHECK") == "" {
+ if os.Getenv("EASYPANEL_SKIP_VERSION_CHECK") != "1" {
reportPanelVersion(ep, endpoint)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Probe the panel version so route drift shows up at boot instead of on the | |
| // first failing RPC. Never fatal: a slow or briefly unreachable panel should | |
| // not stop the server from serving. | |
| if os.Getenv("EASYPANEL_SKIP_VERSION_CHECK") == "" { | |
| reportPanelVersion(ep, endpoint) | |
| } | |
| // Probe the panel version so route drift shows up at boot instead of on the | |
| // first failing RPC. Never fatal: a slow or briefly unreachable panel should | |
| // not stop the server from serving. | |
| if os.Getenv("EASYPANEL_SKIP_VERSION_CHECK") != "1" { | |
| reportPanelVersion(ep, endpoint) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@cmd/grpc-server/main.go` around lines 41 - 46, Update the
EASYPANEL_SKIP_VERSION_CHECK condition around reportPanelVersion so the probe is
skipped only when the environment value equals "1"; run reportPanelVersion for
unset, "0", and all other values.
| // Supported panel range. The route surface this project depends on | ||
| // (services.app.*, services.compose.*, domains.*, logs.*, projects.*) is | ||
| // byte-identical across 2.32.0 through 2.33.1; MinSupportedVersion is the | ||
| // oldest release verified against the pinned route surfaces in testdata, and | ||
| // MaxTestedVersion is the newest. | ||
| const ( | ||
| MinSupportedVersion = "2.32.0" | ||
| MaxTestedVersion = "2.33.1" | ||
| ) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
The declared support floor is not backed by a pinned surface. MinSupportedVersion is 2.32.0, but the oldest fixture in internal/easypanel/testdata/ is panel-surface-2.32.2.json. No fixture covers 2.32.0 or 2.32.1, so TestRequiredRoutesExistInEverySupportedPanel never verifies the routes for the lowest supported release. TestSupportWindowMatchesPinnedSurfaces only asserts oldest >= MinSupportedVersion, so the gap passes silently. Choose one resolution and apply it at both sites.
internal/easypanel/version.go#L14-L22: either setMinSupportedVersionto2.32.2to match the oldest fixture, or add a2.32.0fixture and keep the constant. Also correct the comment, which currently states thatMinSupportedVersionis "the oldest release verified against the pinned route surfaces in testdata".scripts/panel-surface.sh#L18-L22: update the defaultVERSIONSlist so it starts at the chosen floor, keeping the comment on Line 18 accurate.
📍 Affects 2 files
internal/easypanel/version.go#L14-L22(this comment)scripts/panel-surface.sh#L18-L22
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/easypanel/version.go` around lines 14 - 22, Align the supported
version floor with pinned coverage: in internal/easypanel/version.go lines
14-22, either set MinSupportedVersion to 2.32.2 or add a 2.32.0 fixture while
correcting the surrounding comment; in scripts/panel-surface.sh lines 18-22,
update the default VERSIONS list to start at the same chosen floor and keep its
comment accurate.
| if err != nil { | ||
| return Version{}, fmt.Errorf("panel version: %w", err) | ||
| } | ||
| defer resp.Body.Close() |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Handle the resp.Body.Close return value.
golangci-lint errcheck reports the unchecked return on this line. Assign it explicitly to keep the linter green.
🔧 Proposed fix
- defer resp.Body.Close()
+ defer func() { _ = resp.Body.Close() }()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| defer resp.Body.Close() | |
| defer func() { _ = resp.Body.Close() }() |
🧰 Tools
🪛 golangci-lint (2.12.2)
[error] 110-110: Error return value of resp.Body.Close is not checked
(errcheck)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/easypanel/version.go` at line 110, Update the deferred response-body
cleanup in the surrounding HTTP request function to explicitly discard the
return value from resp.Body.Close, satisfying errcheck while preserving the
existing cleanup behavior.
Source: Linters/SAST tools
| """Extract the Easypanel backend route surface from a bundled backend.js. | ||
|
|
||
| Usage: epsurface.py <path-to-backend.js> <out.json> | ||
| """ |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Correct the script name in the usage line.
The usage line names epsurface.py. The file is scripts/extract-panel-surface.py, and scripts/panel-surface.sh invokes it under that name.
📝 Proposed fix
-Usage: epsurface.py <path-to-backend.js> <out.json>
+Usage: extract-panel-surface.py <path-to-backend.js> <out.json>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| """Extract the Easypanel backend route surface from a bundled backend.js. | |
| Usage: epsurface.py <path-to-backend.js> <out.json> | |
| """ | |
| """Extract the Easypanel backend route surface from a bundled backend.js. | |
| Usage: extract-panel-surface.py <path-to-backend.js> <out.json> | |
| """ |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/extract-panel-surface.py` around lines 2 - 5, Correct the usage
example in the module docstring to use the actual script name
extract-panel-surface.py, matching the filename invoked by
scripts/panel-surface.sh.
- scripts/extract-panel-surface.py resolved a schema alias only when the
preceding character was a separator, so `}var uo=g.object({...})` in 2.32.0
looked like an empty input. Match on a non-identifier boundary instead. This
makes 2.32.0 resolve identically to the newer releases.
- Pin 2.32.0 as well, so both ends of the declared support window are backed by
a fixture, and require MinSupportedVersion to equal the oldest pinned surface.
All four pinned releases agree on every route this project uses.
- EASYPANEL_SKIP_VERSION_CHECK is parsed as a boolean, so `=0` no longer skips
the probe.
- The disabled-log-aggregation precheck invalidates the cached settings, so an
operator enabling aggregation takes effect on the next GetLogs call instead of
after the cache TTL. The error message tells callers to retry, so it has to be
true.
- README: language on the error-output fence, refreshed pinned-version notes.
Prepares v0.1.0. Started from two live failures on
panel.srv-opc.ciptadusa.com(Easypanel 2.33.0):GetLogsreturning[BAD_REQUEST] fetch failed, andGetServiceStatusreturning almost nothing for a compose service.Why GetLogs failed
Panel-side, not ours. Extracted
app/backend.jsfrom the official images:Easypanel serves logs only from its own Loki deployment; there is no
docker logsroute anywhere in the panel API. Loki and Promtail are deployed only when log aggregation is enabled, which the panel gates behind a license withadvanced_monitoring. On this panellogs.getSettingsreturnsnulland no license is present, so the panel's ownfetchdies and gets wrapped asBAD_REQUEST: fetch failed.GetLogsnow prechecks and explains:Enabled-but-unreachable Loki is reported separately. Also added the panel's remaining filters (
stream,levels,search,start,end),limitclamping to the panel maximum of 1000, and localInvalidArgumentfor badstreamvalues.Why GetServiceStatus was sparse
inspectServicereturns stored config only, and compose services keepsource.contentrather than an image, so the response had no image and no runtime signal. Now merged with the panel's Docker view viaprojects.getDockerContainersandservices.compose.getDockerServices:{ "status": "running", // running | stopped | unknown "runningContainers": 1, "containers": [{ "name": "pods_hermes-a1-agent-1", "image": "nousresearch/hermes-agent:v2026.8.3", "state": "running", "status": "Up 47 hours" }], "composeServices": ["agent"] }A refused container query degrades to
status: "unknown"with configuration intact instead of failing the RPC.Version pinning
Pulled three separate images and diffed their route surfaces:
latest)Identical route names and input fields, so one code path covers
2.32.0..2.33.1. Surfaces are pinned ininternal/easypanel/testdata/, every route used is declared ininternal/easypanel/routes.go, and tests assert each one still exists with an unchanged input shape.grpc-serverprobesinfo.versionfrom/api/openapi.json(the only version route present in all supported releases;/api/cli.jsonand/api/mcpare 2.33+) and logs whether the panel is inside the window.scripts/panel-surface.shre-pins after an upgrade.Breaking change
GetServiceStatusno longer returns env values by default. The panel stores secrets in the env blob its inspect routes return, and aGRPC_AUTH_TOKENSentry can read every project — the livepods/deploy-everythingresponse contained its ownEASYPANEL_API_KEYandGRPC_AUTH_TOKENS. Keys are kept, values become<redacted>; setinclude_env: truefor clear text.Verification
AuthReject,DeployContainerE2E,DeployComposeE2E,UpdateResources, plus newRuntimeStatusAndLogs(asserts running container payload, the log precondition, local stream rejection, and env redaction on/off).make fmt-check,go vet ./...,go test ./... -count=1all clean.Follow-up
Release is not cut yet: tagging
v0.1.0is what publishes images and binaries.Summary by CodeRabbit
New Features
Bug Fixes
Documentation