Skip to content

Fake 'Successfully published' banner when underlying git push fails (silent deploy failure) #205

@JohannesHoppe

Description

@JohannesHoppe

Summary

When the underlying gh-pages library fails to push (for example, because the authentication token used for HTTPS auth is invalid/revoked), angular-cli-ghpages still prints its success banner and exits 0. CI systems therefore report green builds while nothing is actually deployed.

Observed behavior in a real CI run

🚀 Uploading via git, please wait...
Cloning ***github.com/owner/repo.git into .../node_modules/.cache/gh-pages/...
Cloning into '.../node_modules/.cache/gh-pages/...'...
remote: Invalid username or token. Password authentication is not supported for Git operations.
fatal: Authentication failed for 'https://github.com/owner/repo.git/'
🌟 Successfully published via angular-cli-ghpages! Have a nice day!

The job exits 0. GitHub Actions shows a green checkmark. No commit lands on the target branch.

Impact

In our setup, a GitHub Actions GH_TOKEN secret had silently expired. For about four weeks every Build Backend and Build Frontend run reported success while the build repos received zero new commits. Our downstream auto-deploy (Koyeb pulling from the build repo) therefore served stale code for a month, completely invisibly, including after we pushed fixes that looked successful in Actions logs.

The failure class is: git child process exited non-zero (authentication/push error), but the outer promise resolved.

Root cause (best guess)

src/engine/engine.ts calls:

await ghPages.publish(dir, ghPagesOptions);

and, on resolution, unconditionally logs:

logger.info('🌟 Successfully published via angular-cli-ghpages! Have a nice day!');

There is even a comment noting that a historic Promise bug in gh-pages was believed to be fixed in v5+:

// gh-pages v5+ fixed the Promise bug where errors didn't reject properly
// We can now safely await the promise directly

The evidence above (with gh-pages@6.3.0, as pinned by angular-cli-ghpages@3.0.2) suggests at least one failure class still resolves instead of rejecting — specifically the git clone / auth-failure path invoked before any git push. If gh-pages emits the error only to stderr and resolves, angular-cli-ghpages has no way to know the deploy failed.

Reproducer

  1. Create a GitHub Actions workflow that calls npx angular-cli-ghpages --repo=https://github.com/<owner>/<repo>.git ... using a GH_TOKEN env var whose token is expired or scoped away from the target repo.
  2. Run the workflow.
  3. Observe: fatal: Authentication failed in the log, followed by the 🌟 success banner, and job exit code 0.

Suggested directions (non-prescriptive)

  • Defensive check at the end of publishViaGhPages: capture the child process's exit code (or scan its stderr for fatal: / error:) and throw when seen, instead of trusting the outer promise alone.
  • Optional post-deploy verification: after ghPages.publish() resolves, do a shallow git ls-remote (or the GitHub API) and confirm the branch tip moved to the expected commit. If not, throw.
  • Upstream: open a companion issue at tschaub/gh-pages with the same reproducer so the underlying promise-rejection gap can be tracked there too.

Even a simple "loud warning" (e.g. logger.warn('git reported an error above — aborting') when the stderr stream contained fatal: or error:) would have saved a month of silent stale deploys here.

Happy to help test a fix against the original failing CI if useful.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions