8 ms·
Dear GitHub: no YAML anchors, please
- baobun 1y agoYAML anchors are a welcome feature and will allow us to DRY some of our uglier workflows that currently have a lot of redundancy/duplication. OPs main argument seems to be "I don't have a use for it and find it hard to read so it should be removed".
- woodruffw 1y ago(I'm the author.) I don't think this is a fair characterization: it's not that I don't have a use for it, but that I think the uses are redundant with existing functionality while also making static and human analysis of workflows harder.
- willseth 1y agoI think the main reason you see overwhelming support for anchors is that the existing Actions functionality is typically so cumbersome to implement and often makes it harder to understand a workflow. Anchor syntax is a little esoteric, but otherwise very simple and grokable.
- woodruffw 1y agoTo be clear, I understand why people want to use anchors. The argument isn't that they aren't useful: it's that the juice is not worth the squeeze, and that GitHub's decision to support them reflects a lack of design discretion. Or in other words: if your problem is DRYness, GitHub should be fixing or enhancing the ~dozen other ways in which the components of a workflow shadow and scope with each other. Adding a new cross-cutting form of interaction between components makes the overall experience of using GitHub Actions less consistent (and less secure, per points about static analysis challenges) at the benefit of a small amount of deduplication.
- btreecat 1y agoSo GitHub shouldn't implement the spec because you personally don't like that the spec solves a problem you can optionally solve at another layer?
- woodruffw 1y agoNo; GitHub shouldn't support YAML anchors because it's a deviation from the status quo, and the argument is specifically that the actions ecosystem doesn't need to make analysis any harder than it already is. (As the post notes, neither I nor GitHub appears to see full compliance with YAML 1.1 to be an important goal: they still don't support merge keys, and I'm sure they don't support all kinds of minutiae like non-primitive keys that make YAML uniquely annoying to analyze. Conforming to a complex specification is not inherently a good thing; sometimes good engineering taste dictates that only a subset should be implemented.)
- btreecat 1y ago> No; GitHub shouldn't support YAML anchors because it's a deviation from the status quo, and the argument is specifically that the actions ecosystem doesn't need to make analysis any harder than it already is. > > (As the post notes, neither I nor GitHub appears to see full compliance with YAML 1.1 to be an important goal: they still don't support merge keys, and I'm sure they don't support all kinds of minutiae like non-primitive keys that make YAML uniquely annoying to analyze. Conforming to a complex specification is not inherently a good thing; sometimes good engineering taste dictates that only a subset should be implemented.) That's a long way to say "yes, actually"
- woodruffw 1y ago> That's a long way to say "yes, actually" "Because I don't like it" makes it sound like I don't have a technical argument here, which I do. Do you think it's polite or charitable to reduce peoples' technical arguments into "yuck or yum" statements like this?
- GuinansEyebrows 1y agois your criticism leveled at yaml anchors or github? in my anecdotal experience, yaml anchors were a huge help (and really, really not hard to grasp at a conceptual level) in maintaining uniform build processes across environments.
- woodruffw 1y agoIt is specifically leveled at YAML anchors in GitHub. I don't have a super strong opinion of YAML anchors in other contexts. (This post is written from my perspective as a static analysis tool author. It's my opinion from that perspective that the benefits of anchors are not worth their costs in the specific context of GitHub Actions, for the reasons mentioned in the post.)
- saurik 1y ago"YAML" should mean something. When I saw GitHub Actions supported "YAML", I thought "OK, certainly not my favorite, but I can deal with that", and so I read the YAML specification, saw anchors, and then had to realize the hard way that they didn't work on GitHub Actions, leaving me unsure what even would or wouldn't work going forward. Is this even the only way it differs? I don't know, as they apparently don't use YAML :/. This also means that, if you use an off-the-shelf implementation to parse these files, you're "doing it wrong", as you are introducing a parser differential: I can put code in one of these files that one tool uses and another tool ignores. (Hopefully, the file just gets entirely rejected if I use the feature, but I do not remember what the experience I had was when I tried using the feature myself; but, even that is a security issue.) > Except: GitHub Actions doesn’t support merge keys! They appear to be using their own internal YAML parser that already had some degree of support for anchors and references, but not for merge keys. Well, hopefully they also prioritize fixing that? Doing what GitHub did, is apparently still doing, and what you are wanting them to keep doing (just only in your specific way) is not actually using "YAML": it is making a new bespoke syntax that looks a bit like YAML and then insisting on calling it "YAML" even though it isn't actually YAML and you can neither read the YAML documentation nor use off-the-shelf YAML libraries. Regardless, it sounds like your tool already supports YAML anchors, as your off-the-shelf implementation of YAML (correctly) supports YAML anchors. You are upset that this implementation doesn't provide you source map attribution: that was also a problem with C preprocessors for a long time, but that can and should be fixed inside of the parser, not by deciding the language feature shouldn't exist because of library limitations.
- detaro 1y agoin what ways do they make static analysis harder? Don't they flatten out trivially after parsing?
- woodruffw 1y agoThe flattening out is the problem: most (all?) widely used YAML parsers represent the YAML document using the JSON object model, which means that there's no model or element representation of the anchors themselves. That in turn means that there's no way to construct a source span back to the anchor itself, because the parsed representation doesn't know where the anchor came from (only that it was flattened).
- VGHN7XDuOXPAzol 1y agoThis is something that a custom parser library could figure out, no? The same as how you have format-preserving TOML libraries, for instance. I think it makes way more sense for GitHub to support YAML anchors given they are after all part of the YAML spec. Otherwise, don't call it YAML! (This was a criticism of mine for many years, I'm very glad they finally saw the light and rectified this bug)
- woodruffw 1y ago> This is something that a custom parser library could figure out, no? The same as how you have format-preserving TOML libraries, for instance. Yes, it's just difficult. The point made in the post isn't that it's impossible, but that it significantly changes the amount of of "ground work" that static analysis tools have to do to produce useful results for GitHub Actions. > I think it makes way more sense for GitHub to support YAML anchors given they are after all part of the YAML spec. Otherwise, don't call it YAML! (This was a criticism of mine for many years, I'm very glad they finally saw the light and rectified this bug) It's worth noting that GitHub doesn't support other parts of the YAML spec: they intentionally use their own bespoke YAML parser, and they don't have the "Norway" problem because they intentionally don't apply the boolean value rules from YAML. All in all, I think conformance with YAML is a red herring here: GitHub Actions is already its own thing, and that thing should be easy to analyze. Adding anchors makes it harder to analyze.
- spott 1y agoThe counterpoint is that I don’t want to be an expert in GitHub actions to not repeat myself. YAML anchors are a standard that I can learn and use in a lot of places. The idiosyncrasies of GitHub actions aren’t really useful for me to learn. Just my $0.02
- nirvdrum 1y agoThe argument that this is a security issue isn't very well fleshed out either. As far as I can tell, it boils down to his opinion that this makes YAML harder to read and thus less secure. But, the reality is we have to copy & paste config today and that's a process I've seen fail when a change needs to be made and isn't properly carried forward to all locations. I suppose I could argue that's a security concern as well. Half the argument against supporting YAML anchors appears to boil down some level of tool breakage. While you can rely on simplifying assumptions, you take a risk that your software breaks when that assumption is invalidated. I don't think that's a reason to stop evolving software. I've never seen a project use any of the tools the author listed, but I have seen duplicated config. That's not to say the tools have no value, but rather I don't want to be artificially restricted to better support tools I don't use. I'll grant that the inability to merge keys isn't ideal but, I'll take what I can get.
- a456463 1y agoAs some one that has written massive gitlab pipelines for monoliths and super tiny ones and on boarded teams, YAML anchors are amazing.
- everfrustrated 1y agoAgreed. Anchors is YAMLs real feature. YAML without anchors is just JSON + comments otherwise.
- a_t48 1y agoAnchors will be exceptionally useful for a few workflows for me. We have what is essentially the same setup/teardown for three jobs within one workflow. I’d love to be able to factor that stuff out without introducing yet another yaml file to the repo, this will be a big help.
- dan_manges 1y agoWe support anchors in our CI/CD syntax at RWX, but only in a specific `aliases` section. I think this is a nice compromise. aliases: common-env: &common-env key1: value1 key2: value2 tasks: - key: some-task run: ... env: <<: *common-env https://www.rwx.com/docs/mint/aliases https://www.rwx.com/docs/mint/aliases
- willseth 1y agoYAML anchors may be a sharp tool but no one is forced to use them. I have written many verbose Github workflows that would have benefited from using anchors, and I am relieved to learn I can clean those up now.
- raincole 1y agoIt seems that any data-orient approach would inevitably evolve into a programming language given enough time. One day we might even see for-loop in CSS...
- andreareina 1y agoThere are languages specifically for writing configs. Like dhall https://dhall-lang.org/ https://dhall-lang.org/
- eblume 1y agoThat's my thought as well. I predict we'll be seeing SDK's for generating github workflows by mid-2026. Maybe pulumi will get an extension for it. (I'm well aware that codegen yaml has been a thing for a long time, but I'm thinking about something targeting github workflows _specifically_.) TBH it's getting a bit exhausting watching us go through this hamster wheel again and again and again.
- jerf 1y agoI have a theory that in such cases one might as well just give up and write a Turing-complete language in the first place, as the sort of TC-complete languages we get with this sort of "slowly but surely backed against the wall" situations are way worse than just starting from scratch. I hypothesize a TC-complete language for something like CSS that included deep tracking under the hood for where values are coming from and where they are going would be very useful, i.e., you would have the ability to point at a particular part of the final output and the language runtime could give you a complete accounting of where it came from and what went into making the decisions, could end up giving us the auditability that we really want from the "declarative" languages while giving us the full power of the programming langauges we clearly want. However I don't have the time to try to manifest such a thing myself, and I don't know of any existing language that does what I'm thinking of. Some of the more powerful languages could theoretically do it as a library. It's not entirely unlike the auditing monad I mention towards the end of https://www.jerf.org/iri/post/2958/ https://www.jerf.org/iri/post/2958/ . It's not something I'd expect a general-purpose language to do by default since it would have bad general-purpose performance, but I think for specialized cases of a TC-complete configuration langauge it could have value, and one could always run it as an debugging option and have an optimized code path that didn't track the sources of everything.
- anttiharju 1y agoI think YAML anchors in GitHub Actions are very welcome, for example for DRYing the push/pull_request 'paths:' filters [1]. Now only if they supported paths filter for `workflow_call` [2] event in addition to push/pull_request and my life would be a lot easier. Nontrivial repos have an unfortunate habit of building some sort of broken version of change detection themselves. The limit of 20 unique workflow calls is quite low too but searching the docs for a source maybe they have removed it? It used to say > You can call a maximum of 20 unique reusable workflows from a single workflow file. but now it's max of 4 nested workflows without loops, which gives a lot of power for the more complex repos [3]. Ooh. Need to go test this. [1] https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#example-including-paths https://docs.github.com/en/actions/reference/workflows-and-a... [2] https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#onworkflow_call https://docs.github.com/en/actions/reference/workflows-and-a... [3] https://docs.github.com/en/actions/how-tos/reuse-automations/reuse-workflows#nesting-reusable-workflows https://docs.github.com/en/actions/how-tos/reuse-automations...
- TheDong 1y agoWanna DRY out your github actions yaml? Generate it from Dhall, or cue, or python, or some real language that supports actual abstractions. If your problem is you want to DRY out yaml, and you use more yaml features to do it, you now have more problems, not fewer.
- usrme 1y agoSeconded. I've had huge success with generating workflows with CUE. Would definitely recommend it to anyone struggling with YAML.
- Spivak 1y agoJust introduce a templating language and the CI to generate the yaml as part of your pipeline as way to make it simpler? Above a certain level of complexity, sure. But having nothing in between is an annoying state of affairs. I use anchors in Gitlab pipelines and I hardly curse their names.
- 1y ago
- qwerty2000 1y agoJust because it is expressed in YAML doesn't make YAML the party to blame here. I would say one of the main concerns I have with anything in GitHub Actions related to the word "merge" has to do with identifying the last commit for a merge, not merging of objects in YAML. If you have two workflows... one to handle a PR creation/update and another to address the merge operation, it is like pulling teeth to get the final commit properly identified so you can grab any uploaded artifacts from the PR workflow.
- theamk 1y agoAuthor's replacement for anchors is to use global syntax, like a top-level "env:" block. This is a terrible advice from security endpoint - given that env variables are often used for secrets data, you really _don't_ want them to set them at the top level. The secrets should be scoped as narrow as possible! For example, if you have a few jobs, and some of them need to download some data in first step (which needs a secret), then your choices are (a) copy-paste "env" block 3 times in each step, (b) use the new YAML anchor and (c) set secret at top-level scope. It is pretty clear to me that (c) is the worst idea, security wise - this will make secret available to every step in the workflow, making it much easier for malware to exfiltrate.
- cluckindan 1y agoI agree. OP’s statement ”the need to template environment variables across a subset of jobs suggests an architectural error in the workflow design” does not ring true for cases where you want developers to be able to quickly deploy a separate environment for each development branch, especially if said branch needs to connect to a matching backend/API/other service.
- pacoWebConsult 1y agoCan YAML go away entirely and instead allow pipelines to be defined with an actual language? What benefits does the runner-interpreted yaml-defined pipeline paradigm actually achieve? Especially with runners that can't be executed and tested locally, working with them is a nightmare.
- red_hare 1y agoI'm surprised by this take. I love YAML for this use case. Easy to write and read by hand, while also being easy to write and read with code in just about every language.
- Pxtl 1y agoIt's less about YAML itself than the MS yaml-based API for interacting with build-servers. It's just so hard to check and test and debug.
- everfrustrated 1y agoThis so much this. Vscode has a very good syntax check github actions yaml so it's not yaml that's the problem. It's the workflow for developing pipelines that's the problem. If I had something I could run locally - even in a debug dry-run only form that would go a long way to debugging job dependencies, etc. Testing failure cases flow conditional logic in the expected manner etc.
- TheDong 1y ago> Easy to write and read by hand, while also being easy to write and read with code in just about every language Language implementations for yaml vary _wildly_. What does the following parse as: some_map: key: value no: cap If I google "yaml online" and paste it in, one gives me: {'some_map': {False: 'cap', 'key': 'value'}} The other gives me: {'some_map': {'false': 'cap', 'key': 'value'}} ... and neither gives what a human probably intended, huh?
- 1y ago
- devmor 1y agoObviously they are very useful. I still don't think they should exist in this usage of yaml. Once you allow setting and reading of variables in a configuration file, you lose the safety that makes the format useful. You might as well be using a bash script at that point.
- nirvdrum 1y agoYou already can set and read variables. The `matrix` section is often used to test against multiple versions of software. Environment variables can be referenced. And the project configuration supports both secrets and variables configured at the project level.
- devmor 1y agoSorry, I think my comment was not clear. I think allowing both setting and reading of variables directly in the configuration file is a problem. Not reading variables that have been set outside of the configuration file alone.
- Pxtl 1y agoHonestly, everything about GH actions/AzDO pipelines is infuriating. The poor tooling with poor write-time assertions are just so frustrating. Give me a proper platform that I can run locally on my development machine. but, if those anchors are a blessed standard YAML feature that YAML tools will provide real assertions about unlike the ${{}} stuff that basically you're doing a commit-push-run-wait-without any proper debug tools besides prints? Then yes, they should use them.
- javcasas 1y agoGeneral YAML anchors as implemented by the standard: good (not great, just good). Custom YAML anchors with custom support and surprise corner cases: bad.
- deleted 1y ago[deleted]
- kpcyrd 1y agoFor context: - The complaint is Github using a non-standard, custom fork of yaml - This makes it harder to develop linters/security tools (as those have to explicitly deal with all features available) - The author of this blogpost is also the author of zizmor, the most well-known Github Actions security linter (also the only one I'm aware of)
- techlatest_net 1y ago[dead]
- junon 1y agoI disagree. Instead of anchors we had to rely on third party file change actions to only trigger jobs on certain file path changes, instead of using the built in mechanism, because each job required the list, and the list was long. Using anchors would have improved the security of this, as well as the maintenance. The examples cited don't remotely demonstrate the cases where anchors would have been useful in GA. I agree that YAML is a poor choice of format regardless but still, anchor support would have benefitted a number of projects ages ago.
- OJFord 1y agoOk, now make the 'redundancy' argument with anything other than `env` or `permissions`. I think they should be supported because it's surprising and confusing if you start saying 'actually, it's a proprietary subset of YAML', no more reason needed than that.
- baq 1y ago'Dear GitHub: no YAML, please' would be a so much better title (content optional)
- beder 1y agoA very pedantic point, but merge keys are not part of the YAML spec [1]! Merge keys are a custom type [2], which may optionally be applied during the construction phase of loading. I definitely wouldn't say that merge keys are integral to anchors. (Also, as a personal bias, merge keys are really bad because they are ambiguous, and I haven't implemented them in my C++ yaml library (yaml-cpp) because of that.) [1]: https://yaml.org/spec/1.2.2/ https://yaml.org/spec/1.2.2/ [2]: https://yaml.org/type/merge.html https://yaml.org/type/merge.html
- woodruffw 1y agoYeah, I find the situation here very confusing: I agree that merge keys are not part of YAML 1.2, but they are part of YAML 1.1. The reason they don't appear to be in the "main" 1.1 spec itself is because they were added to 1.1 after 1.1 was already deprecated[1]. [1]: https://ktomk.github.io/writing/yaml-anchor-alias-and-merge-key.html https://ktomk.github.io/writing/yaml-anchor-alias-and-merge-...
- imcritic 1y agoI think the author is nuts. First, he can just not use the feature, not advocate for its removal. Second, his example alternative is wrong: it would set variables for all steps, not just those 2, he didn't think of a scenario where there are 3 steps and you need to have common envs in just 2 of them.
- woodruffw 1y agoThe author does not think he's nuts :-) > First, he can just not use the feature, not advocate for its removal. I maintain a tool that ~thousands of projects use to analyze their workflows and actions. I can avoid using anchors, but I can't avoid downstreams using them. That's why the post focuses on static analysis challenges. > Second, his example alternative is wrong: it would set variables for all steps, not just those 2, he didn't think of a scenario where there are 3 steps and you need to have common envs in just 2 of them. This is explicitly addressed immediately below the example.
- danudey 1y agoWrote a new yaml grepping tool this past weekend and just realized thanks to this that I have a whole new can of worms to keep in mind. Ugh. Turns out it does report values at their targets (which is desirable) but doesn't know or indicate that they're anchors (undesirable). Also tested something with yq - if you tell it to edit a node that is actually from a yaml anchor, it updates the original anchor without warning you that that's what you're doing. Yikes. (For anyone who wants to test it: https://pypi.org/project/yamlgrep/ https://pypi.org/project/yamlgrep/)
- anon7000 1y agoAnchors are so, so useful. Buildkite (which has its own CI pipelines syntax) is a good example. Let’s say I want every pipeline step to run on my custom agents (on my self-hosted infra). I could either copy/paste an identical “agents” property across however many hundreds or thousands of CI steps I have. Or I could use a YAML anchor.
- kazinator 1y agoCommon Lisp has this (and other dialects that imitate the Circle Notation; I think Scheme has it now, Emacs Lisp, TXR lisp, ): E.g. (#1=(a b) c d e #1#) encodes ((a b) c d e (a b)) where the two (a b) occurrences are one object. It can express circular structures: #1=(a b c . #1#) encodes an infinite circular list (a b c a b c a b c ...) The object to be duplicated is prefixed with #<decimal-integer>=. This associates the object with the integer. The integer is later referenced as #<decimal-integer># to replicate it. The thing is, you don't see a lot of this in human-written files, whether they are source code or data. This is not the primary way that Lisp systems use for specifying replicated data in configurations, let alone code. Substructure sharing occurs whether you use the notation or not due to interned symbols. (Plus compilers can deduplicate strings and such.) In (a a a) there is only one object a, a symbol. If you feed the implementation circular source code though, ANSI CL says the behavior is undefined. Some interpreters can handle it under the right circumstances. In particular ones that don't try to do a full macro-expanding code walk before running the code. Compilers, not so much.
- jerjerjer 1y agoI don't think anchors' primary function is to allow global definitions (of variables or whatever), rather it's more like arbitrary templates/snippets to be reused through the YAML file. In GitLab, where YAML anchors have been supported for years, I personally find them very useful —it's the only way of "code" reuse, really. In GitLab there's a special edtor just for .gitlab-ci.yml, which shows the original view and the combined read-only view (with all anchors expanded). I agree that it's hard to point to the specific line of the source code, but it's enough — in case of an error — to output an action name, action property name, and actual property value that caused an error. Based on these three things, a developer can easily find the correct line.
- zft 1y ago>it's the only way of "code" reuse, really. not really. You can also use include/extends pattern. If that is not enough, there is dynamic pipeline generation feature.
- jerjerjer 1y ago> include Interesting, although to me it looks more like a way to split one file into several (which is rather useful). > extends What's the difference with anchors? Looks the same, except works with include (and doesn't work with any other yaml tool). > dynamic pipeline generation Which is even harder to reason about compared to anchors, although certainly powerful.
- plqbfbv 1y agoIn my experience include/extends works well for importing or extending whole jobs, but not so much for defining a small snippet of text that I want to reuse across many jobs, perhaps when overriding stuff. An example of how I normally use them and why I still find them useful: # Imports whole pipeline architecture jobs include: - project: company/ci-templates ref: "master" file: "languages/stack.yaml" # Define a command I need to use exactly the same # across different jobs I'm going to override .vpn_connect: &vpn_connect - cmd1 - cmd2 - cmd3 & job1: extends: imported1 script: - .... - *vpn_connect # 2nd command - ... job2: extends: imported2 script: - ... - ... - *vpn_connect # 3rd command - ...
- bethekidyouwant 1y agoWrite one set of common rules, include them as needed. Seems useful.
- stack_framer 1y agoDear GitHub: No YAML, please. There, that's better.
- louiskottmann 1y agoGitlab has had that for a while, and it's very useful as in-between through dot targets. i.e: .scoped-env: &scoped-env key1: value1 ... Dot targets are ignored semantically, only inheritors make them useful. Then further down you can reuse *scoped-env wherever you need. You can also have anchors on individual lines and compose them. It's useful. The author suggests using ad-hoc syntax, or meta-keys. Gitlab supports that [1] and I use them as well. Different but also combinable uses, for various people. Nothing wrong with it. 1: https://docs.gitlab.com/ci/yaml/#extends https://docs.gitlab.com/ci/yaml/#extends