
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.
catops
Advanced tools
Highly trained cats for managing servers.

CatOps is a very simple NoOps framework for deploying your own ChatOps bot.
Commands you wish to add to your CatOps implementation are added to a plugins
folder in the same directory, and will then be automatically imported and callable
using the function name.
NoOps.
Codify common maintenance procedures.
Unify documentation.
Transparency.
/meow restart server in the chat.Context-aware suggestions, suggest actions and display help depending on context.
Reduce context switching.
Control access.
pip install catopsmeow install [--template] [--target-dir]npm install in the template directory.serverless deployEvery Lambda function needs a handler, which takes arguments (event, context). In this case, it is necessary to respond instantly to the request with a 200 so the handler below calls the actual functionality asynchronously and then returns a 200 response.
import json
from six.moves.urllib.parse import parse_qs
import requests
import boto3
from catops import convert_dispatch
def respond(event, context):
"""Call handler.main asynchronously and then return instant response."""
lambda_client = boto3.client('lambda')
response = {'statusCode':'200'}
# Call actual function asynchronously
lambda_client.invoke(
FunctionName='CatOps-dev-dispatcher',
InvocationType='Event',
Payload=json.dumps(event))
return response
def main(event, context):
"""Main lamda function logic, to be called asynchronously."""
params = parse_qs(event.get('body'))
payload = convert_dispatch(params)
username = params.get('user_name', ['catops'])[0]
# Post to Slack channel
response_url = params.get('response_url')
if type(response_url) is list:
response_url = response_url[0]
r = requests.post(response_url, data=json.dumps(payload))
if not r.ok:
print(r)
print(r.reason)
print(r.text)
return
CatOps works around plugins.
_ are ignored. (_ means they are private and will not be added to the CatOps dispatcher)/catops <functionname> [argv](argv, params)
/catops role --user t.user, argv will contain `['role', '--user', 't.user']{"text": ... , "username": ..., "response_url": ...}."""example.py - example plugin for ChatOps."""
from catops import create_slack_payload
def ping(argv, params):
"""Check is working."""
text = '@{} Meow!'.format(params.get('user_name', ['CatOps'])[0]),
return create_slack_payload(text=text)
service: CatOps
package:
include:
- handler.py
- plugins/**
custom:
pythonRequirements:
slim: true
provider:
name: aws
stage: ${opt:stage, 'dev'}
runtime: python3.6
profile: serverless
# Permissions for the lambda function
# If using boto3, ensure correct permissions
# have been granted to the lambda function
iamRoleStatements:
- Effect: Allow
Action:
- lambda:InvokeFunction
- lambda:InvokeAsync
Resource: "*"
functions:
dispatcher:
handler: handler.main
respond:
handler: handler.respond
events:
- http:
path: ping
method: post
plugins:
- serverless-python-requirements
serverless deploy
serverless invoke --function dispatcher --path /path/to/json/data --log
See examples and templates for more.
# auth.py
def verify_request(event, slack_secret, timeout=True):
"""Verify that Lambda event came from Slack"""
def get_user_slack(event, oauth, team_id=None, channel_id=None):
"""Check whether user exists and is in specified team and channel.
Arguments:
event - AWS Lambda event
oauth - Slack OAUTH token
team_id - Slack team_id (workspace, i.e. BBOXX)
channel_id - Channel user must be in
Returns:
False, err_msg
True, user_dict with id, name, team_id, channel_id, email
"""
# dispatcher.py
def dispatch(command, params=None, plugin_dir='plugins/'):
"""Create Dispatcher object and run parse_command on (command, params)"""
# helpers.py
def get_slack_colour(level):
"""Return Slack colour value based on log level."""
def get_text(params):
"""Return event_text from parse_qs event.get('body')."""
def create_slack_attachment(fallback=None,
color=None,
pretext=None,
author_name=None,
author_link=None,
author_icon=None,
title=None,
title_link=None,
text=None,
fields=None,
image_url=None,
thumb_url=None,
footer=None,
footer_icon=None,
ts=None
):
"""Create slack attachment payload
See https://api.slack.com/docs/message-attachments for more info.
Arguments:
fallback - Required plain-text summary of the attachment
[color] - Colour of the attachment
[pretext] - Optional text that appears above the attachment block
[author_name]
[author_link]
[author_icon] - URL to author icon
[title] - Title of the attachment
[title_link]
[text] - Optional text that appears inside the attachment
[fields] - Array of dicts containing more values
[image_url] - URL to image attached
[thumb_url] - URL to image thumbnail
[footer] - Footer message
[footer_icon] - URL to footer icon
[ts] - timestamp
"""
def create_slack_payload(response_type='ephemeral', text="", attachments=None):
"""Create a Slack payload formatted correctly."""
def convert_dispatch(params, convert_function=None, plugin_dir='plugins/'):
"""Call dispatch and convert the output accordingly into a payload."""
# slack_handler.py
class SlackHandler(logging.Handler):
"""Logger slack_handler which posts json log body to lambda_url."""
# install.py
def install(argv=None):
"""Install catops serverless Slack template."""
# parser.py
class ArgumentParserError(Exception):
"""Error raised by ArgumentParser"""
pass
class CatParser(argparse.ArgumentParser):
"""Overrides error method to throw an error instead of exiting"""
def error(self, message):
raise ArgumentParserError(message)
sudo apt-get install npm
sudo npm install -g serverless
npm install serverless-python-requirements
pip install catops
Install serverless-python-requirements in the same dir as serverless.yml.
FAQs
Highly trained cats for managing servers.
We found that catops 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.