BGGP4 Writeup: Self-Replicating VSCode Workspace
Table of Contents
As soon as I saw the announcement for a new Binary Golf Grand Prix challenge, I knew this was the time I’d finally commit to entering.
Binary Golf Grand Prix 4 begins now!#BGGP4 Theme: "Replicate"
— Binary Golf Association (@binarygolf) June 23, 2023
Challenge Announcement:https://t.co/AX83D5e4xz pic.twitter.com/eRLnUsYXhC
Creating a self-replicating file under size constraints just seemed like such a cool idea, and I knew it would give me an excuse to research something I’d been curious about.
I thought trying a VSCode Workspace file would be fun because it’s a spin on the idea and fits in the “this file isn’t supposed to be executable…” category. Plus after seeing VSCode’s workspace trust warning so often, I was curious if I could make it happen.
My submission is a single json file named x.code-workspace
, where if you open it in VSCode, it will create a copy of itself named “4” and print the number “4”. Contents follow, repo is here.
{"folders":[{"path":"."}],"tasks":{"tasks":[{"label":"x","type":"shell","command":"cp x* 4;ls 4","runOptions":{"runOn":"folderOpen"}}]}}
How VSCode Workspace files work #
Starting off, I knew there were ways to run tasks in the background with VSCode… and I knew it was associated with workspaces, but I didn’t know how the two concepts were related.
So I started by reading up on Workspaces, Workspace files, and tasks.
The upshot is that workspace files are like a single-file version of the workspace folder, a directory named .vscode/
at the root of the workspace.
After a bit of reading and experimenting, I figured out the basic structure of a workspace file. And soon after I figured out how to run a task as soon as the Workspace was opened to get an initial proof-of-concept:
{
"folders": [
{
"path": "."
}
],
"settings": {},
"tasks": {
"version": "2.0.0",
"tasks": [
{
"label": "echo",
"type": "shell",
"command": "cp x.* 4 && echo 4",
"runOptions": {
"runOn": "folderOpen"
},
"presentation": {
"reveal": "always",
}
}
]
}
}
Self-Replication #
The trick is the runOn: "folderOpen"
bit, which allows us to run a shell command, but getting execution on opening usually requires a dialog asking the user if they want to trust the workspace:
The warning does say that doing so may automatically execute commands, so people should know that’s what’s going to happen, right?
But I figured that was still acceptable for the purposes of the challenge because there are some circumstances where a user doesn’t see a warning at all.
Since the extension .code-workspace
is required for the file to be treated as a workspace file, I named the file x.code-workspace
, and then copy by globbing on the name in the shell command.
The rules didn’t specify whether the filename mattered, so I think this is fair because you could really run any shell command; this is just to reduce size.
Size golfing #
At this point, the only remaining goal is to reduce size while maintaining functionality.
So clearly I went through several iterations, but the basic steps were:
- Removed all optional fields
- Tried removing “non-optional” fields, though
version
was really the only one that VSCode’s linter said was mandatory but actually wasn’t - Read the parsing code to see if I could take any other shortcuts (none that I saw)
- Removed all unnecessary whitespace
- Golfed down the copy command itself based on another BGGP writeup: https://rap.sh/Shell_Script_Golf
In the end I got it down to 136 bytes, not bad for a JSON file that puppets a behemoth Electron app into copying itself!
Too much magic (and trust) #
Workspace trust has been on my mind for a while because I’ve seen this warning a ton, and I always felt that the binary decision on “Do you trust the authors of these files” is insufficient and kinda unactionable.
As a user, I’d like to see a few more data points and maybe have more than just a binary decision of “yup, run arbitrary commands on my machine” or “no, please fall back to just being a text editor”. I understand that there’s a ton of things other than just running shell commands on open that could be abused, but I still don’t like it.
Also it turns out that there is an Allow Automatic Tasks
setting that can control whether tasks can automatically run (
mentioned in this GitHub issue), but it’s always been on
in my testing, so trusting the workspace is the only hurdle I found from a default install.
Further, one of the specific scenarios where no trust windows are shown are if a user is working in an already-trusted workspace and opens the workspace file.
When you do this, VSCode will tell you it is a workspace file, and even helpfully give you a button to treat it as such… which in this case triggers the file to copy itself.
One of my complaints about a lot of modern dev work is there’s “too much magic”, meaning there’s a lot going on behind the scenes that devs “shouldn’t need to worry about.”
I don’t know about you, but I don’t like being told “don’t worry about the man behind the green curtain” when I’m developing. I want to see what’s going on under the hood.
All in all, it is a tricky situation because the automatic background task stuff is working as intended and is super helpful for development… but it could also be risky.
Shout-outs #
Thanks to netspooky, tmp.out, and everyone else that helped with BGGP; I had a lot of fun!
Also thanks to the VSCode team, this isn’t meant to be a dig at them at all. I think VSCode is awesome, and I love the open-source approach they’ve taken.
Follow me on Twitter or Mastodon for more occasional random hacks!