deploy manifest and deploy bundle pre-resolve the title before constructing RSConnectExecutor:
main.py:1901: title = title or default_title_from_manifest(file)
main.py:1997: title = title or default_title_from_bundle(file)
Because the executor computes title_is_default = not title, these commands always hand deploy() a non-empty title with title_is_default=False. RSConnectClient.deploy then hits api.py:1145:
if app["title"] != app_title and not title_is_default:
result = self.content_update(app_guid, {"title": app_title}) # PATCH v1/content/{guid}
So every redeploy to an existing --app-id where the derived default differs from the content's real title issues a PATCH /v1/content/{guid}. The derived default is usually junk: for a manifest with no metadata.entrypoint (e.g. anything from R's rsconnect::writeManifest()), _default_title_from_manifest falls back to dirname(manifest_file) — deploying manifest.json by relative path yields the cwd's basename (in our case, the title "inst").
Consequences:
- Trusted publishing is broken for manifest deploys. Connect machine identities are only permitted on the content-get/bundle/deploy/task endpoints;
PATCH /v1/content/:guid is rejected with You don't have permission to perform this operation, failing the whole deploy at the "Deploying bundle" step. Since R content can only be deployed via manifest, every R + trusted-publishing deploy (e.g. through posit-dev/connect-actions) fails.
- With an API key, content is silently renamed to the derived default (our app would have been renamed to "inst").
Repro: create content on Connect with a title, then rsconnect deploy manifest --app-id <guid> manifest.json — observe the PATCH (403 under a trusted-publishing key; silent rename under an API key).
Suggested fix: don't pre-resolve the title in the command functions. Pass the user's --title (possibly None) into the executor so title_is_default stays accurate, and use the manifest/bundle-derived default only where a title is actually needed (content creation). Other deploy subcommands already behave this way, which is why source deploys work under trusted publishing.
deploy manifestanddeploy bundlepre-resolve the title before constructingRSConnectExecutor:main.py:1901:title = title or default_title_from_manifest(file)main.py:1997:title = title or default_title_from_bundle(file)Because the executor computes
title_is_default = not title, these commands always handdeploy()a non-empty title withtitle_is_default=False.RSConnectClient.deploythen hitsapi.py:1145:So every redeploy to an existing
--app-idwhere the derived default differs from the content's real title issues aPATCH /v1/content/{guid}. The derived default is usually junk: for a manifest with nometadata.entrypoint(e.g. anything from R'srsconnect::writeManifest()),_default_title_from_manifestfalls back todirname(manifest_file)— deployingmanifest.jsonby relative path yields the cwd's basename (in our case, the title"inst").Consequences:
PATCH /v1/content/:guidis rejected withYou don't have permission to perform this operation, failing the whole deploy at the "Deploying bundle" step. Since R content can only be deployed via manifest, every R + trusted-publishing deploy (e.g. through posit-dev/connect-actions) fails.Repro: create content on Connect with a title, then
rsconnect deploy manifest --app-id <guid> manifest.json— observe the PATCH (403 under a trusted-publishing key; silent rename under an API key).Suggested fix: don't pre-resolve the title in the command functions. Pass the user's
--title(possiblyNone) into the executor sotitle_is_defaultstays accurate, and use the manifest/bundle-derived default only where a title is actually needed (content creation). Other deploy subcommands already behave this way, which is why source deploys work under trusted publishing.