add ggshield

This commit is contained in:
CJ_Clippy 2024-08-07 11:30:29 -08:00
parent e4b979d61c
commit e6179e20e5
12 changed files with 285 additions and 161 deletions

1
.cache_ggshield Normal file
View File

@ -0,0 +1 @@
{"last_found_secrets": [{"match": "7630852e9a6a0aecb849c91d14d426ca88187886fdf466189d67145856bdac3e", "name": "Generic Password - charts/postgresql/postgresql/templates/secrets.yaml"}]}

5
.gitguardian.yaml Normal file
View File

@ -0,0 +1,5 @@
secret:
ignored_matches:
- match: 7630852e9a6a0aecb849c91d14d426ca88187886fdf466189d67145856bdac3e
name: Generic Password - charts/postgresql/postgresql/templates/secrets.yaml
version: 2

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.venv/
**/.env* **/.env*
*~ *~
packages/**/isolate/ packages/**/isolate/

7
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,7 @@
repos:
- repo: https://github.com/gitguardian/ggshield
rev: v1.30.2
hooks:
- id: ggshield
language_version: python3
stages: [commit]

View File

@ -9,16 +9,21 @@
"kubernetes-helm@latest", "kubernetes-helm@latest",
"k9s@latest", "k9s@latest",
"ffmpeg@latest", "ffmpeg@latest",
"yt-dlp@latest" "yt-dlp@latest",
"python312@latest",
"python312Packages.pip@latest"
], ],
"env": { "env": {
"DEVBOX_COREPACK_ENABLED": "true", "DEVBOX_COREPACK_ENABLED": "true",
"ENV": "development", "ENV": "development",
"KUBECONFIG": "$HOME/.kube/futureporn.yaml" "KUBECONFIG": "$HOME/.kube/futureporn.yaml",
"VENV_DIR": ".venv"
}, },
"shell": { "shell": {
"init_hook": [ "init_hook": [
"echo Welcome to Futureporn devbox" "echo Welcome to Futureporn devbox",
". $VENV_DIR/bin/activate",
"pip install -r requirements.txt"
], ],
"scripts": { "scripts": {
"test": [ "test": [

View File

@ -490,6 +490,148 @@
} }
} }
}, },
"python312@latest": {
"last_modified": "2024-06-12T20:55:33Z",
"plugin_version": "0.0.3",
"resolved": "github:NixOS/nixpkgs/a9858885e197f984d92d7fe64e9fff6b2e488d40#python312",
"source": "devbox-search",
"version": "3.12.3",
"systems": {
"aarch64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/65ackbgqn02p6fy75rksjbp17zj6440j-python3-3.12.3",
"default": true
}
],
"store_path": "/nix/store/65ackbgqn02p6fy75rksjbp17zj6440j-python3-3.12.3"
},
"aarch64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/59siylp1k9i3ch4d9m3vs5jp5z56b5sg-python3-3.12.3",
"default": true
},
{
"name": "debug",
"path": "/nix/store/ji094818a78hrkag26202b21nr5v1pgk-python3-3.12.3-debug"
}
],
"store_path": "/nix/store/59siylp1k9i3ch4d9m3vs5jp5z56b5sg-python3-3.12.3"
},
"x86_64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/nrskm5p85y6751k02ih51bpzfag8g5r8-python3-3.12.3",
"default": true
}
],
"store_path": "/nix/store/nrskm5p85y6751k02ih51bpzfag8g5r8-python3-3.12.3"
},
"x86_64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/zwvdwiw0zg5liz6lkkkqyab035parhld-python3-3.12.3",
"default": true
},
{
"name": "debug",
"path": "/nix/store/wj6mffmpvly3md2hqnq2jj8zrrw5qck9-python3-3.12.3-debug"
}
],
"store_path": "/nix/store/zwvdwiw0zg5liz6lkkkqyab035parhld-python3-3.12.3"
}
}
},
"python312Packages.pip@latest": {
"last_modified": "2024-07-07T07:43:47Z",
"plugin_version": "0.0.2",
"resolved": "github:NixOS/nixpkgs/b60793b86201040d9dee019a05089a9150d08b5b#python312Packages.pip",
"source": "devbox-search",
"version": "24.0",
"systems": {
"aarch64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/2p2wyydd5m787ms85fcic1ap7ql2j2gs-python3.12-pip-24.0",
"default": true
},
{
"name": "man",
"path": "/nix/store/pad6sdd500ikddhym5p2h3krblbazs6k-python3.12-pip-24.0-man",
"default": true
},
{
"name": "dist",
"path": "/nix/store/6wpcdjrk6wj95wb2v7q5zm06cmj9w1c7-python3.12-pip-24.0-dist"
}
],
"store_path": "/nix/store/2p2wyydd5m787ms85fcic1ap7ql2j2gs-python3.12-pip-24.0"
},
"aarch64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/3m2j8ydrz8rj42aramlvh7hkc15izm52-python3.12-pip-24.0",
"default": true
},
{
"name": "man",
"path": "/nix/store/z3lq18q7slp92q7wgqm34s7v4vg222hw-python3.12-pip-24.0-man",
"default": true
},
{
"name": "dist",
"path": "/nix/store/y49wc2lcia8ji5sa9szc7b6gk7mr2mhi-python3.12-pip-24.0-dist"
}
],
"store_path": "/nix/store/3m2j8ydrz8rj42aramlvh7hkc15izm52-python3.12-pip-24.0"
},
"x86_64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/rh3z88c38c9xn52rdkp1swxy0rml3bjv-python3.12-pip-24.0",
"default": true
},
{
"name": "man",
"path": "/nix/store/j9csjm7dq29qpyvwnv48fslqm0b6dwzi-python3.12-pip-24.0-man",
"default": true
},
{
"name": "dist",
"path": "/nix/store/rp5mhjjjll87pa7lmdad5b01wgz8qa91-python3.12-pip-24.0-dist"
}
],
"store_path": "/nix/store/rh3z88c38c9xn52rdkp1swxy0rml3bjv-python3.12-pip-24.0"
},
"x86_64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/9gd8kj409msfv599456ywbyi97izlbr4-python3.12-pip-24.0",
"default": true
},
{
"name": "man",
"path": "/nix/store/57hvcf28az2fx50z6kx3w6ijl0yazy4z-python3.12-pip-24.0-man",
"default": true
},
{
"name": "dist",
"path": "/nix/store/0x4s6vyfivk6fck7lp1dwrg79gp0nvmg-python3.12-pip-24.0-dist"
}
],
"store_path": "/nix/store/9gd8kj409msfv599456ywbyi97izlbr4-python3.12-pip-24.0"
}
}
},
"tilt@latest": { "tilt@latest": {
"last_modified": "2024-07-15T21:47:20Z", "last_modified": "2024-07-15T21:47:20Z",
"resolved": "github:NixOS/nixpkgs/b2c1f10bfbb3f617ea8e8669ac13f3f56ceb2ea2#tilt", "resolved": "github:NixOS/nixpkgs/b2c1f10bfbb3f617ea8e8669ac13f3f56ceb2ea2#tilt",

3
requirements.txt Normal file
View File

@ -0,0 +1,3 @@
pre-commit
ggshield
click

View File

@ -46,42 +46,6 @@ importers:
specifier: ^5.5.3 specifier: ^5.5.3
version: 5.5.4 version: 5.5.4
../..: {}
../../packages/image: {}
../../packages/infra: {}
../../packages/meal: {}
../../packages/old: {}
../../packages/scout: {}
../../packages/storage: {}
../../packages/taco: {}
../../packages/types: {}
../../packages/utils: {}
../../packages/video: {}
../../packages/worker: {}
../capture: {}
../mailbox: {}
../migrations: {}
../next: {}
../strapi: {}
../uppy: {}
packages: packages:
'@babel/code-frame@7.24.7': '@babel/code-frame@7.24.7':

View File

@ -51,15 +51,14 @@ createCommand({
async execute(interaction: Interaction) { async execute(interaction: Interaction) {
await interaction.defer() await interaction.defer()
console.log('interation.data as follows') // console.log('interation.data as follows')
console.log(interaction.data) // console.log(interaction.data)
const options = interaction.data?.options const options = interaction.data?.options
if (!options) throw new Error(`interaction options was undefined. it's expected to be an array of options.`); if (!options) throw new Error(`interaction options was undefined. it's expected to be an array of options.`);
const urlOption = options.find((o) => o.name === 'url') const urlOption = options.find((o) => o.name === 'url')
if (!urlOption) throw new Error(`url option was missing from interaction data`); if (!urlOption) throw new Error(`url option was missing from interaction data`);
const url = ''+urlOption.value const url = ''+urlOption.value
if (!url) throw new Error(`url was missing from interaction data options`); if (!url) throw new Error(`url was missing from interaction data options`);
// const url = (interaction.data?.options?.find(o => o.name === 'url')?.value) ?? undefined;
// respond to the interaction and get a message ID which we will then add to the database Record // respond to the interaction and get a message ID which we will then add to the database Record
const embeds = new EmbedsBuilder() const embeds = new EmbedsBuilder()
@ -75,8 +74,8 @@ createCommand({
const response: InteractionCallbackData = { embeds } const response: InteractionCallbackData = { embeds }
const message = await interaction.edit(response) const message = await interaction.edit(response)
console.log('defferred, interaction message is as follows') // console.log('deferred, interaction message is as follows')
console.log(message) // console.log(message)
if (!message?.id) { if (!message?.id) {
const msg = `message.id was empty, ruh roh raggy` const msg = `message.id was empty, ruh roh raggy`
console.error(msg) console.error(msg)
@ -85,57 +84,8 @@ createCommand({
// @todo create record in db // @todo create record in db
const record = await createRecordInDatabase(url, message.id.toString()) const record = await createRecordInDatabase(url, message.id.toString())
console.log(record) // console.log(record)
}
// if (!interaction.data?.values) throw new Error('interaction data was missing values');
// console.log(`while executing record command, the following values were seen.`)
// console.log(interaction.data.values)
// const embeds = new EmbedsBuilder()
// .setTitle('My Embed')
// .setDescription('This is my new embed')
// .newEmbed()
// .setTitle('My Second Embed')
// await interaction.respond({
// embeds:
// })
},
}) })
// const statusEmbed = new EmbedBuilder()
// .setTitle('Pending')
// .setDescription('Waiting for a worker to accept the job.')
// .setColor(2326507)
// const buttonRow = new ActionRowBuilder<MessageActionRowComponentBuilder>()
// .addComponents([
// new ButtonBuilder()
// .setCustomId('stop')
// .setLabel('Stop Recording')
// .setEmoji('🛑')
// .setStyle(ButtonStyle.Danger),
// ]);
// const command: CreateSlashApplicationCommand = {
// name: 'record',
// description: 'Record a livestream.',
// options: [
// {
// name: 'url',
// description: 'URL of the livestream',
// type: ApplicationCommandOptionTypes.String
// },
// ],
// async execute(interaction: Interaction) {
// const ping = Date.now() - snowflakeToTimestamp(interaction.id)
// const embeds = createEmbeds().setTitle(`The bot ping is ${ping}ms`)
// await interaction.respond({ embeds })
// },
// }
// export default command

View File

@ -3,29 +3,19 @@ import type { RecordingState } from '@futureporn/types'
import { type Task, type Helpers } from 'graphile-worker' import { type Task, type Helpers } from 'graphile-worker'
import { add } from 'date-fns' import { add } from 'date-fns'
import prettyBytes from 'pretty-bytes' import prettyBytes from 'pretty-bytes'
import { import { EmbedsBuilder, type Component } from '@discordeno/bot'
type APIEmbedField,
Client,
GatewayIntentBits,
TextChannel,
ActionRowBuilder,
ButtonBuilder,
type MessageActionRowComponentBuilder,
ButtonStyle,
EmbedBuilder,
Guild
} from 'discord.js';
interface Payload { interface Payload {
recordId: number; record_id: number;
} }
function assertPayload(payload: any): asserts payload is Payload { function assertPayload(payload: any): asserts payload is Payload {
if (typeof payload !== "object" || !payload) throw new Error("invalid payload"); if (typeof payload !== "object" || !payload) throw new Error("invalid payload");
if (!payload.recordId) throw new Error(`recordId was absent in the payload`); if (!payload.record_id) throw new Error(`record_id was absent in the payload`);
} }
@ -111,7 +101,8 @@ async function getRecordFromDatabase(recordId: number) {
export const updateDiscordMessage: Task = async function (payload, helpers: Helpers) { export const updateDiscordMessage: Task = async function (payload, helpers: Helpers) {
try { try {
assertPayload(payload) assertPayload(payload)
const { recordId } = payload const { record_id } = payload
const recordId = record_id
helpers.logger.info(`updateDiscordMessage() with recordId=${recordId}`) helpers.logger.info(`updateDiscordMessage() with recordId=${recordId}`)
const record = await getRecordFromDatabase(recordId) const record = await getRecordFromDatabase(recordId)
const { discord_message_id, recording_state, file_size, url } = record const { discord_message_id, recording_state, file_size, url } = record
@ -133,64 +124,97 @@ export const updateDiscordMessage: Task = async function (payload, helpers: Help
function getStatusEmbed({ function getStatusEmbed({
recordingState, recordId, fileSize, url recordingState, recordId, fileSize, url
}: { fileSize: number, recordingState: RecordingState, recordId: number, url: string }) { }: { fileSize: number, recordingState: RecordingState, recordId: number, url: string }) {
let title, description, color, fields; const embeds = new EmbedsBuilder()
title = `Record ${recordId}` .setTitle(`Record ${recordId}`)
fields = [ .setFields([
{ name: 'Status', value: 'Pending', inline: true }, { name: 'Status', value: 'Pending', inline: true },
{ name: 'Filesize', value: `${fileSize} bytes (${prettyBytes(fileSize)})`, inline: true }, { name: 'Filesize', value: `${fileSize} bytes (${prettyBytes(fileSize)})`, inline: true },
{ name: 'URL', value: url, inline: false }, { name: 'URL', value: url, inline: false },
] as APIEmbedField[] ])
if (recordingState === 'pending') { if (recordingState === 'pending') {
description = "Waiting for a worker to accept the job." embeds
color = 2326507 .setDescription("Waiting for a worker to accept the job.")
.setColor(2326507)
} else if (recordingState === 'recording') { } else if (recordingState === 'recording') {
description = 'The stream is being recorded.' embeds
color = 392960 .setDescription('The stream is being recorded.')
.setColor(392960)
} else if (recordingState === 'aborted') { } else if (recordingState === 'aborted') {
description = "The recording was stopped by the user." embeds
color = 8289651 .setDescription("The recording was stopped by the user.")
.setColor(8289651)
} else if (recordingState === 'ended') { } else if (recordingState === 'ended') {
description = "The recording has stopped." embeds
color = 10855845 .setDescription("The recording has stopped.")
.setColor(10855845)
} else { } else {
description = 'The recording is in an unknown state? (this is a bug.)' embeds
color = 10855845 .setDescription('The recording is in an unknown state? (this is a bug.)')
.setColor(10855845)
} }
return new EmbedBuilder().setTitle(title).setDescription(description).setColor(color).setFields(fields) return embeds
} }
function getButtonRow(state: RecordingState) { function getButtonRow(state: RecordingState) {
let id, label, emoji, style;
const button = new Component()
.setType("BUTTON")
// // Button with raw types
// const button2 = new Component()
// .setType(2)
// .setStyle(4)
// .setLabel("DO NOT CLICK")
// .setCustomId("12345")
// .toJSON();
// const actionRow = new Component()
// .setType("ACTION_ROW")
// .setComponents(button, button2)
// .toJSON();
// return actionRow
// Message to send
// const messageOptions = { content: "hello", components: [actionRow] };
// await client.helpers.sendMessage(channelId, messageOptions); // You can also use the Message Structure
if (state === 'pending') { if (state === 'pending') {
id = 'stop'; button
label = 'Cancel'; .setCustomId('stop')
emoji = '❌'; .setLabel('Cancel')
style = ButtonStyle.Danger; .setEmoji('❌')
.setStyle('DANGER')
} else if (state === 'recording') { } else if (state === 'recording') {
id = 'stop'; button
label = 'Stop Recording'; .setCustomId('stop')
emoji = '🛑'; .setLabel('Stop Recording')
style = ButtonStyle.Danger; .setEmoji('🛑')
.setStyle('DANGER')
} else if (state === 'aborted') { } else if (state === 'aborted') {
id = 'retry'; button
label = 'Retry Recording'; .setCustomId('retry')
emoji = '🔄'; .setLabel('Retry Recording')
style = ButtonStyle.Success; .setEmoji('🔄')
.setStyle('SUCCESS')
} else if (state === 'ended') { } else if (state === 'ended') {
id = 'download'; button
label = 'Download Recording'; .setCustomId('download')
emoji = '📥'; .setLabel('Download Recording')
style = ButtonStyle.Primary; .setEmoji('📥')
.setStyle('PRIMARY')
} else { } else {
id = 'unknown'; button
label = 'Unknown State'; .setCustomId('unknown')
emoji = '🤔'; .setLabel('Unknown State')
style = ButtonStyle.Secondary; .setEmoji('🤔')
.setStyle('SECONDARY')
} }
const actionRow = new Component
return new ActionRowBuilder<MessageActionRowComponentBuilder>() return new ActionRowBuilder<MessageActionRowComponentBuilder>()
.addComponents([ .addComponents([
new ButtonBuilder() new ButtonBuilder()

View File

@ -9,17 +9,17 @@
CREATE FUNCTION public.tg__add_job() RETURNS trigger CREATE FUNCTION public.tg__add_job() RETURNS trigger
LANGUAGE plpgsql SECURITY DEFINER LANGUAGE plpgsql SECURITY DEFINER
SET search_path TO 'pg_catalog', 'public', 'pg_temp' SET search_path TO 'pg_catalog', 'public', 'pg_temp'
AS $$ AS $$
begin begin
PERFORM graphile_worker.add_job(tg_argv[0], json_build_object( PERFORM graphile_worker.add_job(tg_argv[0], json_build_object(
'url', NEW.url, 'url', NEW.url,
'record_id', NEW.id 'record_id', NEW.id
), max_attempts := 12); ), max_attempts := 12);
return NEW; return NEW;
end; end;
$$; $$;
CREATE TRIGGER record CREATE TRIGGER record

View File

@ -0,0 +1,21 @@
CREATE FUNCTION public.tg__update_discord_message() RETURNS trigger
LANGUAGE plpgsql SECURITY DEFINER
SET search_path TO 'pg_catalog', 'public', 'pg_temp'
AS $$
begin
PERFORM graphile_worker.add_job('update_discord_message', json_build_object(
'record_id', NEW.record_id
), max_attempts := 3);
return NEW;
end;
$$;
-- when a record is updated, we add a job in graphile to update_discord_message
CREATE TRIGGER record_update
AFTER UPDATE ON api.records
FOR EACH ROW
EXECUTE PROCEDURE public.tg__update_discord_message('update_discord_message');