Compare commits

...

2 Commits

Author SHA1 Message Date
herel 3a4f58621a doc: add openapi.json 2025-09-02 10:31:59 +02:00
herel a63cf97638 chore: secure deploy 2025-09-02 10:30:08 +02:00
4 changed files with 140 additions and 0 deletions
+15
View File
@@ -20,6 +20,12 @@ spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
runAsNonRoot: true
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
automountServiceAccountToken: false
terminationGracePeriodSeconds: 3
containers:
- image: noaas
imagePullPolicy: IfNotPresent
@@ -31,6 +37,8 @@ spec:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 15
periodSeconds: 20
resources:
limits:
cpu: 1
@@ -45,3 +53,10 @@ spec:
- all
privileged: false
readOnlyRootFilesystem: true
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: noaas
+1
View File
@@ -7,6 +7,7 @@ resources:
- service.yaml
- ingress.yaml
- netpol.yaml
- pdb.yaml
images:
- name: noaas
newName: <my-harbor-url>/library/no-as-a-service
+9
View File
@@ -0,0 +1,9 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: noaas-pdb
spec:
minAvailable: 1
selector:
matchLabels:
app: noaas
+115
View File
@@ -0,0 +1,115 @@
{
"openapi": "3.0.3",
"info": {
"title": "No-as-a-Service API",
"description": "A lightweight API that returns random rejection or \"no\" reasons. Perfect for any scenario: personal, professional, student life, dev life, or just because.",
"version": "1.0.0",
"contact": {
"name": "herel",
"url": "https://gitea.parano.ch/herel/no-as-a-service"
}
},
"servers": [
{
"url": "https://no.parano.ch",
"description": "Production server"
}
],
"paths": {
"/": {
"get": {
"summary": "Get a random rejection reason",
"description": "Returns a randomly selected excuse or rejection reason from a collection of 1000+ universal \"no\" responses.",
"operationId": "getRandomReason",
"responses": {
"200": {
"description": "Successful response with a random rejection reason",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReasonResponse"
}
}
}
},
"429": {
"description": "Rate limit exceeded",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
},
"/health": {
"get": {
"summary": "Health check endpoint",
"description": "Returns the health status of the service for Kubernetes readiness probes.",
"operationId": "getHealth",
"responses": {
"200": {
"description": "Service is healthy",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HealthResponse"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"ReasonResponse": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"description": "A randomly selected rejection reason",
"example": "This feels like something Future Me would yell at Present Me for agreeing to."
}
},
"required": ["reason"]
},
"HealthResponse": {
"type": "object",
"properties": {
"status": {
"type": "string",
"description": "Health status of the service",
"example": "ok"
}
},
"required": ["status"]
},
"ErrorResponse": {
"type": "object",
"properties": {
"error": {
"type": "string",
"description": "Error message",
"example": "Too many requests, please try again later. (120 reqs/min/IP)"
}
},
"required": ["error"]
}
}
},
"tags": [
{
"name": "Reasons",
"description": "Endpoints for getting random rejection reasons"
},
{
"name": "Health",
"description": "Health check endpoints"
}
]
}