Symlinks aren't handled correctly
Opened this issue · 5 comments
Unsure if this should be here, or in the ghcommit-action repo. It appears likely there's an assumption being made about the file modes when generating the commit blobs. This causing this utility (and dependent action) to generate defunct commits.
Reproducer: Create a new, or modify an existing, symlink to file in the repo. Run the utility (or Github action).
Expected result: the symlink is created/updated to point to the target file.
Actual result: the symlink points to a non-existent file. The name of this file is the contents of the symlink target.
As I'm able to use another action achieve a similar result successfully (qoomon/actions--create-commit), I presume this isn't a limitation of the GH API, but something specific to its usage here.
I also suspect it would be in ghcommit-action, however, my initial attempts at recreating are inconclusive at the moment. The ghcommit-action runs git status --porcelain=v1
(with other flags) and a new symlink looks identical to a new file.
my initial attempts at recreating are inconclusive at the moment.
The reproducer I outlined above still works. Here it is in essentially bare repo
qoomon (correct): https://github.com/tophercullen/scratch/pull/3/files
Planetscale (incorrect): https://github.com/tophercullen/scratch/pull/4/files
As seen in those PRs, the ghcommit-action is creating a defunct symlink commit.
You can also see this by pulling the branch and checking the file system structure. This is the result:
#ls -lah symlinks/
thelink.txt -> 'blahblahlbahblah'$'\n'
As you can see, and as noted above, the link name is the contents of the symlink target.
@tophercullen Thanks for those.
I did a quick skim of the qoomon action repo (search) yesterday and it appears it does not use the graphQL createCommitOnBranch
mutation that ghcommit
uses. Instead it uses the REST commit API and if a github app token is used it is able to create commits signed by github's web-flow.gpg key.
From the https://github.com/qoomon/actions--create-commit README:
Commits getting signed, if a GitHub App token (ghs_***) is used and will be marked as verified in the GitHub web interface.
And this is documented by github here: https://github.com/qoomon/actions--create-commit/blob/main/lib/github.ts
Signature verification for bots will only work if the request is verified and authenticated as the GitHub App or bot and contains no custom author information, custom committer information, and no custom signature information, such as Commits API.
After reading that my next debug step would be to determine if symlinks are supported by the createCommitOnBranch
graphql mutation. I suspect it is not. I have not tested it myself yet, but based on what I saw yesterday I assume the answer is no based on how the output from git status --porcelain=v1
does not distinguish between regular file or symlink in its output, which in turn means both types are passed to ghcommit
with the --add
flag.
The createCommitBranch
mutation takes a CreateCommitOnBranchInput which is includes a FileChanges object which has two attributes: additions
+ deletions
. The additions
input takes a path and base64 encoded file contents as described here.
This leads me to believe that symlinks are not supported by the graphql API, and some googling led me to this: https://github.com/shogo82148/actions-commit-and-create-pr/
Currently (on 2022-01-03), the createCommitOnBranch mutation doesn't support file types (i.e. regular file, symlink, submodule, ...). All files will be committed as regular files. You can't create executable files, symlinks, submodules, and so on.
I am led to believe symlinks will just not be possible with ghcommit
.
The purpose of ghcommit
+ ghcommit-action
is to be the simplest, low friction way of getting verified commits on a branch via CI workflows (github actions or others). Given this limitation I think the landscape for verified commits from CI workflows (or other app/robot contexts) is:
- GPG keys. You can give your CI workflow or application a GPG key. The downside here is a static private key in your CI that needs to be rotated regularly to maintain good security practices (ie: people leaving joining a project, company, etc)
- REST commit API with Github App token. The downside is the overhead of setting up a github app (or potentially many if you want to isolate by repo) and rotating the key.
- The
createCommitOnBranch
graphql API as implemented byghcommit
andghcommit-action
. Lowest friction method. No static tokens or keys to be rotated, works with the short-lifetime GITHUB_TOKEN's issued to github-actions workflows.
Unless I discover some new information that refutes any of the above, what I think I will do is modify the README to include the following and then close this issue:
- Add the https://github.com/qoomon/actions--create-commit + github app token as an alternative
- Document the limitations of the
createCommitOnBranch
graphql mutation
A lot to digest, so I apologize ahead of time if I missed and/or misunderstood something.
Given this limitation I think the landscape for verified commits from CI workflows (or other app/robot contexts) is:...
This is indeed the problem I am solving (e.g. requiring signed commits). However, the solutions described don't seem accurate. Something about option 2 or 3 is off, and is why I opened this issue.
If you look those PRs again, you will see that both PR commits are signed and verified with the same key ID. But I have not setup any custom Github Apps. The token in use for both workflows is the short-lifetime GITHUB_TOKEN's issued to github-actions workflows. See the workflow files and this doc.
I do know the custom app setup you refer to. I do need to use such a thing for PRs workflows as the default actions token isn't scoped for team membership, which is required for adding reviewers in certain other actions.
- Add the https://github.com/qoomon/actions--create-commit + github app token as an alternative
Just to reiterate, the current implementation of qoomon in that scratch repo, does not use a custom github app token. The workflow as defined creates signed/verified commits with symlinks correctly using the short-lifetime GITHUB_TOKEN's issued to github-actions workflows.
- Document the limitations of the createCommitOnBranch graphql mutation
The docs indicate to me a file contents only limitation. In addition to symlinks, other non-content changes will be missed. The only one I could think of off hand, are file permissions. I added a simple reproducer to that same scratch repo that adds execute to a file. Predictably, this change was committed with the qoomon action, and notably absent in ghcommit commit.
Even if documented, these limitations can be exceptionally confusing for users. As-is, the ghcommit actions logs lead the user to believe the change(s) will be committed, and then is incorrect or silently dropped due to the API used. Obviously, my expectation would be for this type of action to support changes typical to a git add; git commit;
etc. flow. But If that is untenable for some reason (seems like different API is required), I'd much prefer that the action error if it involves unsupported changes, rather than pushing bad commits or silently dropping changes, and then indicating success.
@tophercullen If the qoomon action is able to create verified commits with the default GITHUB_TOKEN
issued to workflows then that is the superior way to do signed commits from GHA workflows. And that is what I was wondering when I wrote the above. When I have time I will test that out and consider archiving ghcommit and ghcommit-action and moving over to qoomon. ty