Reload versions when reiniting.
Fix a bug where one-line? wasn't being applied to data.
Bump lua version to 5.4.7.
In the northern ocean there is a fish, called the k'un, I do not know how many thousand li in size. This k'un changes into a bird, called the p'eng. Its back is I do not know how many thousand li in breadth. When it is moved, it flies, its wings obscuring the sky like clouds.
When on a voyage, this bird prepares to start for the Southern Ocean, the Celestial Lake. And in the Records of Marvels we read that when the p'eng flies southwards, the water is smitten for a space of three thousand li around, while the bird itself mounts upon a great wind to a height of ninety thousand li, for a flight of six months' duration.
An IRC bot written in Fennel.
$ make pengbot
$ ./pengbot irc.libera.chat 6667 my-pengbot "#pengbot" "#otherchan"
Don't worry if you see it write out an error message that says
fatal: destination path 'checkout' already exists and is not an empty directory.
;
this comes from git initializing the checkout of Fennel.
Note that this does not use TLS to connect; it should not be used with any sensitive data.
Commands can be addressed directly to the bot's nick. In the first given channel, the bot will also listen to commands prefixed with a comma.
Run ,help
to get a list of commands. The main commands are:
,set TERM DEFINITION
: store a term and its definition,get TERM
: retrieve a term's definition,forget TERM
: delete a term's definition,eval FORM
: evaluate a piece of Fennel code and print return value,compile FORM
: print the output from compiling a piece of code,multi-eval VERSION FORM
: run a piece of code in a specific Fennel version,multi-compile VERSION FORM
: compile in a specific Fennel version,versions
: list available versions of Fennel,reinit VERSION
: reset environment for a specific Fennel version,pull
: pull the latest versions from Fennel's git repositoryPengbot can run code against arbitrary versions of Fennel in order to
demonstrate code in IRC channels against old versions, and how things
have changed over time. the ,pull
command allows you to bring in new
versions which may not have even existed when Pengbot was launched!
It stores dictionary data (from set
command) in the data/
directory
that it's launched from. No limits are in place to prevent it from
filling up the disk yet, so disable that command if you're worried.
Requirements: Lua 5.3/5.4/luajit and luasocket.
Pengbot is written in a somewhat experimental style based on
capabilities. The entry point (main.fnl
) and
capabilities.fnl
file are run with full access to the entire system,
and the rest of the program is run in a restricted environment where
the only access to the outside world comes from capabilities that are
passed around from one function to the next.
Beyond that, inside the restricted environment, input which comes in from users over IRC is run in an even more restricted environment, this time even isolated to the specific version of Fennel that the user requested.
This serves a kind of dual purpose; the most obvious is that the
abolition of ambient authority makes the system dramatically more
secure even in the face of serious bugs. An attacker who finds a
remote-code-execution flaw in the code which handles user input will
only gain access to the capabilities needed by the function which they
are able to compromise. In the worst case scenario, this would be the
caps.os
and caps.io
tables, which contain functions capable of
running only a very limited set of commands defined in main.fnl
or
functions for writing to the disk, but only for paths described in
main.fnl
.
The second purpose is as a sort of organizational tool. Because there
is no ambient authority in the code inside the outer environment, it's
easy to tell the level of access of a function just by looking at its
argument list. If it takes conn
then it can do basically anything
(within the overall capability restrictions of the application still;
it can't execute arbitrary commands) but only a small number of
functions take this argument. Likewise if it takes caps
then it can
access any outside capability, but much more common are functions
which take only a single capability, or functions which take none of
the above and can be assumed to either be pure functions or functions
which only make changes to tables.
This helps you see at a glance what kind of function you're looking at, greatly aiding the ability to orient yourself quickly in any file.
Copyright © 2018-2023 Phil Hagelberg and contributors
Distributed under the GNU General Public License version 3 or later; see file LICENSE.