Skip to content

feat(serverless): deploy a packaged source from a URL with --from - #174

Merged
danmrichards merged 14 commits into
mainfrom
feat/serverless-deploy-from-url
Nov 6, 2026
Merged

danmrichards merged 14 commits into
mainfrom
feat/serverless-deploy-from-url

Conversation

@felixsanz

@felixsanz felixsanz commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

deploy only takes a local path today, so deploying a published example means a clone, a cd and a command, and anything that wants to offer the deploy has no way to know what the app needs.

--from <url> fetches a zip whose root holds the app's files and a runware.yaml recording the deploy options, then deploys what that file describes:

runware serverless deploy --from https://runware.ai/docs/serverless/examples/echo.zip

no new api surface. the manifest's keys map one to one onto flags deploy already accepts, so reading the file and passing the flags by hand produce the same application. a flag passed on the command line wins over the file, so one archive goes to another gpu type or another --id without being edited.

two things worth a look in review:

  • --from only creates. a manifest names an id, and deploying it over an app that already has that id would roll the archive out as that app's next version, running this code with the secrets, environment variables and volumes already attached. an existing id is refused and points at --id. there is a test that runs the command and asserts no write reaches the api
  • the archive comes off the network, so from.go treats it as hostile: entries that climb out of the directory, absolute paths, backslash traversal, symlinks, a file count past the cap and a download past the source-upload limit are all refused, each with a test

the manifest also checks the app id against the server's AppId pattern. with --from that id comes out of a file the person deploying did not write, and the api's own answer names the field without naming the rule

verified end to end against production: created an app from the public url with nothing but --from, with the gpu type and entry file coming from the manifest, invoked it and deleted it

make lint, make test and make check-go-fix are clean, and make docs is regenerated


notes for review

copilot reviewed this twice and everything it raised is fixed, with tests, except one thing i would rather you decided on since it is your packer:

on windows the executable bit cannot survive the unpack. --from writes the archive to a temp directory and the existing packer reads it back, deriving each entry's mode from Stat. windows has no execute bit, so a container archive whose dockerfile runs a bundled script directly would deploy with that script at 0644 and fail to start.

fixing it means carrying the zip's own modes through to the repack, which is a new field on packedFile and a new parameter on collectFiles, writeArchive, packDirectory and packContainerDirectory — shared code every deploy goes through, not just --from.

i left it alone because the exposure is narrow: it needs windows, a third-party archive, a container source, and a script the image executes directly. none of the published runware templates can hit it, and i checked rather than assumed — every entry in all fifteen is 0644.

happy to do it in this pr or as a follow-up, whichever you prefer.

@coderabbitai

coderabbitai Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. To trigger a review, include coderabbit-review in the PR description. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 809157c8-cde7-4176-9392-17043768d326

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

Share

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unbounded response draining defeats the download cap, container sources silently ignore incompatible flags, and archive extraction strips executable permissions that deployed apps may require.

3 open issues
What changed in this PR

Adds serverless deploy --from <url> to deploy packaged applications through the existing deployment flow, using a root-level runware.yaml for configuration.

Changes:

  • Downloads and extracts ZIP sources with path validation and resource limits.
  • Validates manifest options and merges them with explicit CLI flags taking precedence.
  • Adds manifest and archive tests, updates argument-validation tests, and documents URL-based deployment.
File Description
internal/​cmd/​serverless/​pack_test.go Shares source-file constants across tests.
internal/​cmd/​serverless/​manifest.go Defines manifest parsing, validation, and flag-merge helpers.
internal/​cmd/​serverless/​manifest_test.go Tests manifest validation and override precedence.
internal/​cmd/​serverless/​init_test.go Reuses the shared entry-file constant.
internal/​cmd/​serverless/​from.go Implements bounded downloads and validated ZIP extraction.
internal/​cmd/​serverless/​from_test.go Tests fetching, extraction, and hostile archive rejection.
internal/​cmd/​serverless/​deploy.go Integrates --from and manifest-derived deployment options.
internal/​cmd/​serverless/​deploy_test.go Tests URL-source argument combinations and conflicts.
docs/​runware_serverless_deploy.md Documents --from, manifest behavior, and examples.

Review effort: Balanced

Comment thread internal/cmd/serverless/deploy.go Resolved
Comment thread internal/cmd/serverless/from.go Resolved
Comment thread internal/cmd/serverless/from.go Resolved
@felixsanz
felixsanz requested review from danmrichards and a balanced review from Copilot November 4, 2026 15:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Archive extraction loses executable permissions, unbounded response draining defeats download limits, and manifest-selected container deployments silently ignore code-only flags.

3 open issues

Review effort: Balanced

@felixsanz
felixsanz marked this pull request as draft November 4, 2026 16:08
@felixsanz
felixsanz requested a balanced review from Copilot November 4, 2026 16:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Archive extraction does not bound implicit directory creation, allowing hostile archives to exhaust local disk space or inodes.

1 open issue
3 previously missed issues

In code that hasn't changed since last review

High severity Implicit directories bypass archive extraction limits

internal/​cmd/​serverless/​from.go:105

The entry and byte caps do not bound implicit directories: 2,000 empty entries with distinct, deeply nested paths can make MkdirAll create far more than 2,000 directories. A hostile --from archive can therefore exhaust local disk space or inodes and make extraction and cleanup very slow. Count implicit directories toward a cumulative budget, or enforce a path-depth limit, before either MkdirAll call in unpackEntry.

Medium severity Env-file values cannot override manifest variables

internal/​cmd/​serverless/​deploy.go:362

When a manifest defines envVars.LOG_LEVEL: info, deploying with --env-file production.env containing LOG_LEVEL=debug still sends info. This branch injects the manifest values as inline pairs, and buildEnvironmentVariables applies those after the explicitly supplied env files. Apply manifest variables before command-line env files, or suppress them when --env-file is supplied, so an explicit flag can override the manifest as documented.

Medium severity YAML environment values are unquoted twice

internal/​cmd/​serverless/​manifest.go:207

YAML decoding has already interpreted quoting, but these assignments subsequently pass through buildEnvironmentVariables → splitEnvAssignment → unquote. A YAML value such as PAYLOAD: '"ready"' therefore reaches the application as ready rather than the literal JSON string "ready". Preserve the decoded YAML values when validating and merging environment variables instead of applying shell/dotenv unquoting to them again.

3 resolved since last review

Review effort: Balanced

Comment thread internal/cmd/serverless/from_test.go Resolved
@felixsanz
felixsanz marked this pull request as ready for review November 4, 2026 16:54
@felixsanz
felixsanz requested a balanced review from Copilot November 4, 2026 16:54

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Archive extraction permits Windows path traversal that can overwrite local files and fails to budget implicit parent directories, risking disk or inode exhaustion.

4 open issues
1 resolved since last review

Review effort: Balanced

Comment thread internal/cmd/serverless/from.go Resolved
Comment thread internal/cmd/serverless/from.go Resolved
Comment thread internal/cmd/serverless/from.go Resolved
Comment thread internal/cmd/serverless/manifest.go Resolved

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The ZIP record cap does not bound implicit parent directories created during extraction, allowing small hostile archives to exhaust disk space or inodes and cause prolonged extraction or cleanup.

4 open issues

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Human assessment is needed to evaluate environment-variable loss, duplicate ZIP-entry permission risks, and untested manifest-based updates to existing apps.

2 open issues
2 resolved since last review

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Duplicate ZIP destinations can leave executable scripts without execute permission, creating a container startup failure risk that requires human assessment.

2 open issues

Review effort: Balanced

@danmrichards danmrichards left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an end-to-end test for deploy --from. The redeploy rule that the PR description names has no test.

A follow-up is fine for the Windows executable bit. Open a ticket and link it here.

Comment thread internal/cmd/serverless/deploy.go Resolved
Comment thread internal/cmd/serverless/deploy.go Resolved
Comment thread internal/cmd/serverless/from.go Resolved
Comment thread internal/cmd/serverless/deploy.go Resolved
Comment thread internal/cmd/serverless/from.go Resolved
@felixsanz

Copy link
Copy Markdown
Contributor Author

Addressed in 5319a04, 098f345 and ad63230.

The blocking test. TestDeployFrom_CreatesFromTheManifest and TestDeployFrom_RedeploysAnExistingApp both run deploy --from through cmd.Execute() against an httptest API, one creating and one updating. The redeploy case is the rule you named: marking gpu-type as changed in the --from branch makes it fail with --gpu-type applies to create only, so the test holds the rule rather than describing it.

The https downgrade. archiveClient carries a CheckRedirect that refuses a redirect leaving https, and keeps the default limit of 10 so only the downgrade changed. Tested at the rule, because an httptest TLS server signs with a CA the client does not trust.

Two entries on one path. unpackArchive records each regular entry's resolved path and refuses the second one that names it. Directory entries are not counted, since a directory and the files under it are not a collision.

What a redeploy does not apply. An update sends only AppSource, so the command now names the manifest sections it drops (volumes, envVars, secrets, compute, whichever the manifest carried) and points at apps scale and apps env-vars. Silent before.

Still open: the --env-var and --env-file asymmetry, which is a behavior choice rather than a fix, and the follow-up ticket for the Windows executable bit.

@felixsanz

Copy link
Copy Markdown
Contributor Author

9830895 takes the last one too. --env-var is now additive over the manifest rather than instead of it.

buildEnvironmentVariables already read the manifest map before --env-file and before the --env-var pairs, so the precedence was right and the --from branch was dropping the map whenever the flag was passed. It now passes it either way, and one flag overrides one key.

TestDeployFrom_EnvVarOverridesOneManifestKey fixes it: a manifest carrying MODEL_REVISION and CACHE_DIR, deployed with --env-var MODEL_REVISION=abc123 --env-var EXTRA=1, has to create with all three. Restoring the old guard makes it fail with CACHE_DIR missing.

The --from help now states the asymmetry that remains on purpose: --env-var and --env-file set one key over the manifest's, while --volume, --requirement and --secret replace its whole list.

…y-from-url

# Conflicts:
#	internal/cmd/serverless/deploy_test.go

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Critical issues allow case-colliding archive entries to silently overwrite files and lose executable metadata during Windows repacking, potentially preventing deployed applications from starting.

3 open issues

Review effort: Balanced

Comment thread internal/cmd/serverless/from.go Resolved
@danmrichards

Copy link
Copy Markdown
Collaborator

todo: Open a ticket for the Windows executable bit and link it here. A follow-up PR is fine for the fix itself.

@felixsanz

Copy link
Copy Markdown
Contributor Author

ticket for the windows executable bit: https://runware.atlassian.net/browse/RUNSERV-1660

also one behavior change from your RFC comment, since it lands here rather than there: --from only creates now. an id that already exists is refused and points at --id, because deploying over it would roll the archive out as that app's next version and run this code with the secrets, env vars and volumes already attached. so TestDeployFrom_RedeploysAnExistingApp became TestDeployFrom_RefusesAnExistingApp, the unapplied-sections warning is gone with the path that needed it, and the pr description is updated. an update from a url can get its own flag when something asks for one

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Executable ZIP permissions are lost on Windows, potentially preventing deployed containers from starting, and the refusal test fails to detect uploads performed before refusal.

2 open issues
2 resolved since last review

Review effort: Balanced

Comment thread internal/cmd/serverless/deploy_test.go Resolved

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Human assessment is needed because parent-directory casing conflicts can produce platform-dependent package paths and break imports in Linux containers.

No open issues 🎉

2 resolved since last review

Review effort: Balanced

@danmrichards
danmrichards merged commit 877ce63 into main Nov 6, 2026
5 checks passed
@danmrichards
danmrichards deleted the feat/serverless-deploy-from-url branch November 6, 2026 13:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants