
Research
SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains
An emerging npm supply chain attack that infects repos, steals CI secrets, and targets developer AI toolchains for further compromise.
bertdotbill
Advanced tools
Table of Contents generated with DocToc
Think Katacoda, but instead of a website with learning examples, you have a web app that creates hands-on lessons from markdown-formatted, jina-templated documents, complete with a web terminal for interactive practice.
Here's a screenshot:

Notice the menu dropdown for Available Lessons. The entries are generated dynamically as defined in the app's configuration file.
Note You'll need a minimum python version of 3.7 for the app to work
You can install the app in any of the following ways:
pip install bertdotbillgit clone https://github.com/berttejeda/bert.bill.git
cd bert.bill
yarn compile:ui:dev
pip install .
pip install -e . insteadpip install git+http://www.github.com/berttejeda/bert.bill.git,Using the provided sample config bill.config.yaml.example, you can create your own default configuration file, ensuring the following:
bill -f path/to/your/config.yamlbill -f http://some.website.com/path/to/your/config.yamlbillpython ./bertdotbill/app.pyUsage information can be obtained by invoking the executable with the --help flag, as with: bill --help or python ./bertdotbill/app.py --help.
The help output should be similar to:
usage: app.py [-h] [--username USERNAME] [--password PASSWORD]
[--lesson-url LESSON_URL]
[--static-assets-folder STATIC_ASSETS_FOLDER]
[--config-file CONFIG_FILE] [--cors-origin CORS_ORIGIN]
[--logfile-path LOGFILE_PATH] [--host-address HOST_ADDRESS]
[--port PORT]
[--webterminal-host-address WEBTERMINAL_HOST_ADDRESS]
[--webterminal-port WEBTERMINAL_PORT]
[--open-browser-delay OPEN_BROWSER_DELAY]
[--logfile-write-mode {a,w}] [--config-file-templatized]
[--api-only] [--all-in-one] [--debug] [--verify-tls]
[--no-render-markdown]
[run]
Bert's Interactive Lesson Loader (BILL)
positional arguments:
run
optional arguments:
-h, --help show this help message and exit
--username USERNAME, -U USERNAME
Username, if the URL requires authentication
--password PASSWORD, -P PASSWORD
Password, if the URL requires authentication
--lesson-url LESSON_URL, -url LESSON_URL
The URL for the lesson definition
--static-assets-folder STATIC_ASSETS_FOLDER, -S STATIC_ASSETS_FOLDER
Explicity specify the folder for static HTML assets
--config-file CONFIG_FILE, -f CONFIG_FILE
Path to app configuration file
--cors-origin CORS_ORIGIN, -o CORS_ORIGIN
Override CORS origin pattern
--logfile-path LOGFILE_PATH, -L LOGFILE_PATH
Path to logfile
--host-address HOST_ADDRESS, -l HOST_ADDRESS
Override default host address
--port PORT, -p PORT Override default listening port
--webterminal-host-address WEBTERMINAL_HOST_ADDRESS, -wh WEBTERMINAL_HOST_ADDRESS
Override default listening host address for the
webterminal socket
--webterminal-port WEBTERMINAL_PORT, -wp WEBTERMINAL_PORT
Override default listening port for the webterminal
socket
--open-browser-delay OPEN_BROWSER_DELAY, -bd OPEN_BROWSER_DELAY
Override default time in seconds to delay when opening
the system's web browser
--logfile-write-mode {a,w}, -w {a,w}
File mode when writing to log file, 'a' to append, 'w'
to overwrite
--config-file-templatized, -fT
Render configuration via jinja2 templating
--api-only Don't serve static assets, only start API
--all-in-one, -aio Run the shell websocket process alongside app
--debug
--verify-tls Verify SSL cert when downloading web content
--no-render-markdown, -nomarkdown
npm install yarnyarn installpip install -r requirements.txtyarn clean && yarn compile:ui:devyarn start:devIf you want to make changes to the UI, you'll need to launch the
web instance with yarn start:dev:parcel.
Once parcel begins serving up the HTML assets, you can make changes to UI components and they will re-render on-the-fly.
The configuration file is read by the Flask API process, and is a YAML-formatted file.
As mentioned above, a sample configuration file is provided: bill.config.yaml.example
If no configuration is specified via the cli, the web app will attempt to find the config file in the following locations:
Do review the comments in the sample file, as these explain how the sections are interpreted/handled by the UI.
If no settings can be found, the app will resort to its defaults, see defaults.py
As such, the defaults settings call for the import of an external config, hosted in my bert.lessons repo:
see bert.lessons/bill.config.yaml
This external config is where I am listing all of my (mostly) hand-crafted tutorials and learning materials.
As already mentioned, lessons are Markdown-formatted files interpreted as jinja templates.
You can define a lesson catalog in the configuration file.
If these files are stored in a password-protected web location, you'll need to specify credentials in the auth.global section of the config file.
Per-lesson credentials are not yet implemented, but will be in a future version.
To add to the templating goodies provided by the Jinja library, I've exposed the OS Environment via the environment key of the sessions object.
This means you should be able to reference any OS-level environment variable in your lesson content, e.g.
# Overview
Hello {{ session['environment']['USERNAME'] }}, welcome to Lesson 1
Every lesson rendered through the app includes a web-based terminal emulator component that allows for practicing the lesson material.
These web terminals are embedded in the user interface, available at its footer and as a slide-in from the right (click Utils to reveal).
As mentioned before, the underlying technology for these web terminals is xterm.js.
As such, the xterm.js component requires a websocket to a bash process.
By default, the bert.bill desktop app will attempt to connect to a local instance of the websocket via http://127.0.0.1:10000/.
You can get this websocket running either by:
bill or bertdotbill/app.py scripts with the -aio flag passed indocker run --rm -it --name aiohttp -p 10000:10000 berttejeda/aiohttp-websocket-bashEither of the commands above will start the websocket and bash process on the target platform on port 10001 by default.
Feel free to adjust either approach to your need.
FAQs
Bert's Interactive Lesson Loader
We found that bertdotbill demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
An emerging npm supply chain attack that infects repos, steals CI secrets, and targets developer AI toolchains for further compromise.

Company News
Socket is proud to join the OpenJS Foundation as a Silver Member, deepening our commitment to the long-term health and security of the JavaScript ecosystem.

Security News
npm now links to Socket's security analysis on every package page. Here's what you'll find when you click through.