14 Commits
Author SHA1 Message Date
Lucas RayanandClaude Sonnet 5.5 6f061e16bc ci: o ci chamado pelo release herda os secrets
CI / Tipos e testes (push) Successful in 59s
CI / Imagem Docker (linux/arm64) (push) Successful in 1m12s
CI / Trivy (dependências e segredos) (push) Successful in 9s
Release / Plano (reaproveitar a imagem?) (push) Successful in 4s
Release / ci (push) Skipped
Release / Publica a imagem (linux/arm64) (push) Successful in 31s
Release / Cria a release no Gitea (push) Successful in 6s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 21:52:58 -03:00
Lucas RayanandClaude Sonnet 5.5 b43bd5e37a fix(docker): corrige as vulnerabilidades da imagem final (apk upgrade; sem npm no runtime)
Release / Plano (reaproveitar a imagem?) (push) Successful in 6s
CI / Trivy (dependências e segredos) (push) Successful in 6s
CI / Tipos e testes (push) Successful in 1m0s
CI / Imagem Docker (linux/arm64) (push) Failing after 37s
Release / ci (push) Failing after 1m44s
Release / Publica a imagem (linux/arm64) (push) Skipped
Release / Cria a release no Gitea (push) Skipped
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 21:49:49 -03:00
Lucas RayanandClaude Sonnet 5.5 522805c826 ci: login no registro só antes de publicar
CI / Tipos e testes (push) Successful in 1m0s
CI / Trivy (dependências e segredos) (push) Successful in 6s
CI / Imagem Docker (linux/arm64) (push) Failing after 51s
Release / ci (push) Failing after 2m0s
Release / Publica a imagem (linux/arm64) (push) Skipped
Release / Cria a release no Gitea (push) Skipped
Release / Plano (reaproveitar a imagem?) (push) Successful in 5s
Build, Trivy e smoke test não precisam de credencial.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 21:46:19 -03:00
Lucas RayanandClaude Sonnet 5.5 4ea17cbac2 ci: volta ao secret REGISTRY_TOKEN para publicar no registro
Release / Plano (reaproveitar a imagem?) (push) Successful in 4s
CI / Tipos e testes (push) Successful in 1m0s
CI / Trivy (dependências e segredos) (push) Successful in 7s
CI / Imagem Docker (linux/arm64) (push) Failing after 6s
Release / ci (push) Failing after 1m13s
Release / Publica a imagem (linux/arm64) (push) Skipped
Release / Cria a release no Gitea (push) Skipped
O registro do Gitea recusa o token do job (unauthorized).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 21:44:15 -03:00
Lucas RayanandClaude Sonnet 5.5 3645c6cbc8 ci: autentica no registro com o token do job, sem secret
Release / Plano (reaproveitar a imagem?) (push) Successful in 4s
CI / Tipos e testes (push) Successful in 57s
CI / Trivy (dependências e segredos) (push) Successful in 6s
CI / Imagem Docker (linux/arm64) (push) Failing after 7s
Release / ci (push) Failing after 1m15s
Release / Publica a imagem (linux/arm64) (push) Skipped
Release / Cria a release no Gitea (push) Skipped
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 21:41:44 -03:00
Lucas RayanandClaude Sonnet 5.5 450537ea7e fix(docker): imagem final sem privilégios (nginx-unprivileged, porta 8080)
Release / Plano (reaproveitar a imagem?) (push) Successful in 5s
CI / Tipos e testes (push) Successful in 1m1s
CI / Trivy (dependências e segredos) (push) Successful in 7s
CI / Imagem Docker (linux/arm64) (push) Failing after 7s
Release / ci (push) Failing after 1m20s
Release / Publica a imagem (linux/arm64) (push) Skipped
Release / Cria a release no Gitea (push) Skipped
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 21:39:30 -03:00
Lucas RayanandClaude Sonnet 5.5 f1ab23ab14 fix(ci): scripts executáveis
Release / Plano (reaproveitar a imagem?) (push) Successful in 5s
CI / Tipos e testes (push) Successful in 1m2s
CI / Trivy (dependências e segredos) (push) Failing after 6s
Release / ci (push) Failing after 1m9s
CI / Imagem Docker (linux/arm64) (push) Skipped
Release / Publica a imagem (linux/arm64) (push) Skipped
Release / Cria a release no Gitea (push) Skipped
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 21:36:07 -03:00
Lucas RayanandClaude Sonnet 5.5 ab7f532456 ci: imagem construída do código, esteira para os runners do Gitea e changelog
Release / Plano (reaproveitar a imagem?) (push) Failing after 4s
Release / ci (push) Skipped
Release / Publica a imagem (linux/arm64) (push) Skipped
Release / Cria a release no Gitea (push) Skipped
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 21:35:00 -03:00
Lucas Rayan 47586bcc7b fix: update healthcheck command to use CMD-SHELL for improved compatibility 2026-07-10 16:50:12 -03:00
Lucas Rayan Guerra 393ce8bee1 Update healthcheck URL in docker-compose.yml 2026-07-10 16:43:49 -03:00
Lucas Rayan Guerra 1ef1429466 Update healthcheck and port mapping in docker-compose 2026-07-10 16:42:36 -03:00
Lucas Rayan Guerra ba8265f820 Remove port mapping for service 'pss' 2026-07-10 16:33:38 -03:00
Lucas Rayan Guerra 6630aedc75 Update healthcheck command and start period 2026-07-10 16:28:22 -03:00
Lucas Rayan Guerra 578c746771 Add healthcheck configuration to docker-compose
Add healthcheck to ensure service availability
2026-07-10 16:19:00 -03:00
20 changed files with 537 additions and 47 deletions

No files matched your search

+10 -2
View File
@@ -1,5 +1,13 @@
node_modules node_modules
dist/ dist
dist.tar.gz
.git .git
.gitignore .gitea
.gitattributes
.claude
.wolf
.superset
docs
*.md *.md
.DS_Store
*.log
+1
View File
@@ -0,0 +1 @@
* text=auto eol=lf
+119
View File
@@ -0,0 +1,119 @@
name: CI
# Documentação e configuração de ferramenta não mudam nada que a suíte teste.
# Na main não roda por push: o release.yml é quem a chama, e só quando a imagem
# precisa ser reconstruída; rodar nos dois repetiria a mesma suíte no mesmo commit.
# Sem gatilho de pull_request: o push da branch já valida o mesmo commit, e os
# dois juntos rodariam tudo duas vezes (o repositório não recebe PR de fork).
#
# A imagem é construída aqui uma única vez, em arm64 (a arquitetura do servidor),
# testada e publicada como inputs-<hash>. Ao fazer o merge, o release encontra
# essa tag e só aplica os nomes novos, sem rodar nem construir nada de novo.
on:
push:
branches-ignore: [main]
paths-ignore: ['**.md', 'LICENSE', 'CITATION.cff', 'paper.md', 'references.bib', 'docs/**', '.claude/**', '.wolf/**', '.superset/**', 'scripts/release-notes.sh']
schedule:
- cron: '0 9 * * 1' # toda segunda: reavalia com a base de vulnerabilidades nova
workflow_call:
permissions:
contents: read
concurrency:
group: ci-${{ gitea.ref }}
cancel-in-progress: true
jobs:
verificar:
name: Tipos e testes
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
# tsc -b é o mesmo que o build faz antes do Vite; aqui falha antes de gastar a imagem.
- run: npx tsc -b
- run: npm test
# Trivy roda pela imagem oficial: o trivy-action clona o repositório do Trivy
# do mesmo servidor do workflow, que aqui é o Gitea, e não o GitHub.
# O workspace do job é um volume que o daemon não enxerga, então os arquivos
# entram no container com `docker cp` em vez de `-v`.
seguranca:
name: Trivy (dependências e segredos)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Repositório
run: |
cid=$(docker create --network host -v trivy-cache:/root/.cache/ -w /src aquasec/trivy:0.70.0 \
fs --scanners vuln,secret,misconfig --severity HIGH,CRITICAL --exit-code 1 .)
docker cp . "$cid:/src"
docker start -a "$cid"
status=$(docker inspect -f '{{.State.ExitCode}}' "$cid")
docker rm "$cid" >/dev/null
exit "$status"
# Só começa depois das verificações baratas: um teste quebrado não gasta um
# build de imagem. Roda no runner arm64, o mesmo tipo do servidor, então o
# que é escaneado e testado é a imagem que vai ao ar.
imagem:
name: Imagem Docker (linux/arm64)
needs: [verificar, seguranca]
runs-on: ubuntu-24.04-arm
env:
REGISTRY: git.lucasrguerra.dev.br
steps:
- uses: actions/checkout@v4
# Conteúdo já publicado (re-push, tag num commit já validado): nada a fazer.
- id: plano
run: scripts/plano-imagem.sh "$REGISTRY" "${{ gitea.repository }}" >> "$GITHUB_OUTPUT"
# `docker build` simples, no daemon persistente do runner: as camadas e o
# cache mount do npm sobrevivem entre execuções. Um buildx criaria um
# BuildKit novo, e vazio, a cada job.
- name: Build
if: ${{ steps.plano.outputs.reuse != 'true' }}
run: docker build -t pss:ci .
- name: Trivy na imagem
if: ${{ steps.plano.outputs.reuse != 'true' }}
run: |
docker run --rm --network host -v trivy-cache:/root/.cache/ -e DOCKER_HOST=tcp://127.0.0.1:2375 aquasec/trivy:0.70.0 \
image --severity HIGH,CRITICAL --exit-code 1 pss:ci
# A SPA sobe, cai no index nas rotas internas e entrega os assets com
# cache imutável (scripts/smoke-imagem.sh).
- name: A imagem sobe e responde
if: ${{ steps.plano.outputs.reuse != 'true' }}
run: |
docker run -d --name pss-ci -p 127.0.0.1:3998:8080 pss:ci
status=0
scripts/smoke-imagem.sh http://127.0.0.1:3998 || status=1
docker rm -f pss-ci >/dev/null
exit "$status"
# O login fica por último: build, Trivy e smoke não precisam de credencial.
- if: ${{ steps.plano.outputs.reuse != 'true' }}
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ gitea.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
# Passou em tudo: publica a mesma imagem que foi testada, sem reconstruir.
- name: Publica inputs-<hash>
if: ${{ steps.plano.outputs.reuse != 'true' }}
run: |
tag="${{ steps.plano.outputs.image }}:inputs-${{ steps.plano.outputs.inputs }}"
docker tag pss:ci "$tag"
docker push "$tag"
+129
View File
@@ -0,0 +1,129 @@
name: Release
# Publica a imagem no registro de containers do Gitea depois de um merge em main,
# e de novo com tag semver quando uma tag v* é enviada. O servidor só faz pull.
# Precisa do secret REGISTRY_TOKEN no repositório (token do Gitea com write:package):
# o registro recusa o token do job.
on:
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
concurrency:
group: release
cancel-in-progress: false
env:
REGISTRY: git.lucasrguerra.dev.br
jobs:
# A imagem só depende dos arquivos que entram no build, não da documentação nem
# da configuração de ferramentas. O push da branch já a construiu, testou e
# publicou como inputs-<hash>; quando essa tag existe (o caso normal de um
# merge, uma tag num commit validado, um merge só de docs), não há o que
# construir: as tags novas apontam para o manifesto existente.
plano:
name: Plano (reaproveitar a imagem?)
runs-on: ubuntu-latest
outputs:
inputs: ${{ steps.plano.outputs.inputs }}
reuse: ${{ steps.plano.outputs.reuse }}
image: ${{ steps.plano.outputs.image }}
steps:
- uses: actions/checkout@v4
- id: plano
run: scripts/plano-imagem.sh "$REGISTRY" "${{ gitea.repository }}" >> "$GITHUB_OUTPUT"
# Nada é publicado sem a suíte completa passar antes. Pulada quando a imagem é
# reaproveitada: o mesmo conteúdo já passou por ela.
ci:
needs: plano
if: ${{ needs.plano.outputs.reuse != 'true' }}
uses: ./.gitea/workflows/ci.yml
# Workflows reutilizáveis não herdam os secrets sozinhos: o login no registro precisa deles.
secrets: inherit
publicar:
name: Publica a imagem (linux/arm64)
needs: [plano, ci]
# ci é pulado, e não bem-sucedido, quando a imagem é reaproveitada.
if: ${{ !cancelled() && needs.plano.result == 'success' && (needs.ci.result == 'success' || needs.plano.outputs.reuse == 'true') }}
# O único runner é arm64 e o servidor de destino (Oracle) também, então a
# imagem é construída nativamente, sem emulação.
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
# Se o ci chamado acima acabou de publicar a imagem (push direto na main),
# o plano lá de cima está desatualizado: confere de novo antes de construir.
- id: replano
run: scripts/plano-imagem.sh "$REGISTRY" "${{ gitea.repository }}" >> "$GITHUB_OUTPUT"
- uses: docker/setup-buildx-action@v4
- name: Autentica no registro
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ gitea.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Metadados
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ needs.plano.outputs.image }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest
type=sha,format=long
- name: Build e push
if: ${{ steps.replano.outputs.reuse != 'true' }}
uses: docker/build-push-action@v7
with:
context: .
platforms: linux/arm64
push: true
tags: |
${{ steps.meta.outputs.tags }}
${{ needs.plano.outputs.image }}:inputs-${{ needs.plano.outputs.inputs }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ needs.plano.outputs.image }}:buildcache
cache-to: type=registry,ref=${{ needs.plano.outputs.image }}:buildcache,mode=max
# Mesmo manifesto, nomes novos: nenhuma camada é lida nem escrita.
- name: Aplica as tags à imagem existente
if: ${{ steps.replano.outputs.reuse == 'true' }}
run: |
tags=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}')
docker buildx imagetools create $tags "${{ needs.plano.outputs.image }}:inputs-${{ needs.plano.outputs.inputs }}"
# Cria a entrada em "Releases" quando a execução é de uma tag v*. Roda depois
# de publicar a imagem, com as notas da seção do CHANGELOG.md.
release:
name: Cria a release no Gitea
needs: [plano, publicar]
# Explícito, como o publicar: o ci acima é pulado quando a imagem é
# reaproveitada, e o success() implícito pularia este job também.
if: ${{ !cancelled() && needs.publicar.result == 'success' && startsWith(gitea.ref, 'refs/tags/v') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Release
env:
TAG: ${{ gitea.ref_name }}
TOKEN: ${{ gitea.token }}
API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
IMAGE: ${{ needs.plano.outputs.image }}
run: |
scripts/release-notes.sh "$TAG" "$IMAGE" > notes.md
pre=false; case "$TAG" in *-*) pre=true ;; esac
jq -n --arg tag "$TAG" --arg name "PSS ${TAG#v}" --rawfile body notes.md --argjson pre "$pre" \
'{tag_name:$tag, name:$name, body:$body, prerelease:$pre}' > release.json
curl -fsS -X POST "$API/releases" -H "Authorization: token $TOKEN" \
-H 'Content-Type: application/json' -d @release.json
+7 -16
View File
@@ -1,19 +1,10 @@
!**/glob-import/dir/node_modules node_modules
.DS_Store
.idea
.pnpm-store
*.cpuprofile
*.local
*.log
/.vscode/
/docs/.vitepress/cache
/docs/.vitepress/.temp
/packages/vite/LICENSE
dist dist
dist-ssr dist-ssr
explorations dist.tar.gz
node_modules *.local
playground-temp *.log
temp .DS_Store
TODOs.md .idea
/.vscode/
.eslintcache .eslintcache
+79
View File
@@ -0,0 +1,79 @@
# Changelog
Everything notable in PSS is recorded here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project follows
[Semantic Versioning](https://semver.org/).
## [Unreleased]
## [1.3.3] - 2026-11-01
### Changed
- The code, the container image and the releases now live on Gitea
(`git.lucasrguerra.dev.br`). The deployment pulls the image from its registry.
- The `Dockerfile` is multi-stage: it builds Vite from source inside the image instead
of unpacking a `dist.tar.gz` committed to the repository (removed, along with the
`build:release` script). The final stage is `nginx-unprivileged`: the container runs
as the `nginx` user and listens on port 8080 instead of 80 (Trivy DS-0002).
- New CI on Gitea runners (`.gitea/workflows`): types, 282 tests, Trivy on the repository
and on the image, and an image smoke test. The image is built once per content hash and
reused by the release, so a merge or a tag on an already validated commit rebuilds nothing.
- Repository links in `package.json`, `CITATION.cff`, the READMEs and `CONTRIBUTING.md`
point to Gitea. `.gitattributes` forces LF line endings.
### Fixed
- `docker-compose.yml` healthcheck uses `CMD-SHELL` and the correct local URL, and the
port mapping honours `PORT`.
## [1.3.2] - 2026-03-25
### Added
- Regression tests for Round Robin scheduling with threads.
## [1.3.1] - 2026-03-25
### Added
- `ThreadMetricsChart` and per-thread metrics.
### Changed
- Improvements to the Gantt chart and the metrics panel.
## [1.3.0] - 2026-03-24
### Added
- Multilevel Feedback Queue (MLFQ) scheduling algorithm.
- Thread scheduler.
## [1.2.0] - 2026-03-23
### Added
- English documentation, a `CONTRIBUTING.md`, the JOSS paper and a Zenodo DOI in
`CITATION.cff`.
- Multilevel Queue (MLQ) scheduling algorithm and its documentation.
### Changed
- License switched to MIT.
- Scheduling algorithms refactored into a class-based `BaseAlgorithm` structure, with
the engine and tests updated and new algorithm and metrics documentation.
## [1.0.0] - 2026-03-23
### Added
- First release of the browser-based CPU scheduling simulator: core scheduling engine,
algorithms (including Priority Round Robin), Gantt chart with context-switch handling,
UI components and Docker setup.
[Unreleased]: https://git.lucasrguerra.dev.br/lucasrguerra/pss/compare/v1.3.3...HEAD
[1.3.3]: https://git.lucasrguerra.dev.br/lucasrguerra/pss/compare/v1.3.2...v1.3.3
[1.3.2]: https://git.lucasrguerra.dev.br/lucasrguerra/pss/compare/v1.2.0...v1.3.2
[1.2.0]: https://git.lucasrguerra.dev.br/lucasrguerra/pss/compare/v1.0.0...v1.2.0
[1.0.0]: https://git.lucasrguerra.dev.br/lucasrguerra/pss/releases/tag/v1.0.0
+1 -1
View File
@@ -6,7 +6,7 @@ version: 1.2.0
date-released: "2026-03-23" date-released: "2026-03-23"
license: MIT license: MIT
url: "https://pss.lucasrguerra.dev.br" url: "https://pss.lucasrguerra.dev.br"
repository-code: "https://github.com/lucasrguerra/pss" repository-code: "https://git.lucasrguerra.dev.br/lucasrguerra/pss"
doi: "10.5281/zenodo.19197235" doi: "10.5281/zenodo.19197235"
identifiers: identifiers:
- type: doi - type: doi
+4 -4
View File
@@ -10,7 +10,7 @@ This document provides guidelines and instructions for contributing to this proj
This section guides you through submitting a bug report for PSS. Following these guidelines helps maintainers and the community understand your report, reproduce the behavior, and find related reports. This section guides you through submitting a bug report for PSS. Following these guidelines helps maintainers and the community understand your report, reproduce the behavior, and find related reports.
If you find a bug, please create an issue on GitHub and include: If you find a bug, please create an issue on Gitea and include:
- A clear and descriptive title. - A clear and descriptive title.
- Exact steps to reproduce the problem. - Exact steps to reproduce the problem.
- What you expected to happen, and what actually happened. - What you expected to happen, and what actually happened.
@@ -37,10 +37,10 @@ To contribute code, you'll need to set up the project locally.
#### Installation Steps #### Installation Steps
1. **Fork the repository** on GitHub. 1. **Fork the repository** on Gitea.
2. **Clone your fork** locally: 2. **Clone your fork** locally:
```bash ```bash
git clone https://github.com/YOUR_USERNAME/pss.git git clone https://git.lucasrguerra.dev.br/YOUR_USERNAME/pss.git
cd pss cd pss
``` ```
3. **Install dependencies**: 3. **Install dependencies**:
@@ -78,7 +78,7 @@ If you add a new feature, please include appropriate tests covering the new func
```bash ```bash
git commit -m "feat: add awesome new feature" git commit -m "feat: add awesome new feature"
``` ```
4. Push your branch to your fork on GitHub: 4. Push your branch to your fork on Gitea:
```bash ```bash
git push origin feature/my-awesome-feature git push origin feature/my-awesome-feature
``` ```
+19 -8
View File
@@ -1,13 +1,24 @@
# ── Production image ── # syntax=docker/dockerfile:1
FROM nginx:alpine
# ── Build: compila o Vite a partir do código, sem artefato pré-construído ──
FROM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm npm ci
COPY . .
RUN npm run build
# ── Imagem final: nginx sem privilégios (usuário nginx, porta 8080) e os estáticos ──
FROM nginxinc/nginx-unprivileged:alpine
# Aplica as correções de segurança do Alpine publicadas depois da imagem base.
USER root
RUN apk upgrade --no-cache
COPY nginx.conf /etc/nginx/conf.d/default.conf COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
# Unpack pre-built Vite output USER nginx
COPY dist.tar.gz /usr/share/nginx/html/ EXPOSE 8080
RUN tar -xzf /usr/share/nginx/html/dist.tar.gz --strip-components=1 -C /usr/share/nginx/html \ HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
&& rm /usr/share/nginx/html/dist.tar.gz CMD wget -q --spider http://127.0.0.1:8080/ || exit 1
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"] CMD ["nginx", "-g", "daemon off;"]
+30 -3
View File
@@ -35,7 +35,7 @@ A live demo is available at: **https://pss.lucasrguerra.dev.br/**
```bash ```bash
# Clone the repository # Clone the repository
git clone https://github.com/lucasrguerra/pss.git git clone https://git.lucasrguerra.dev.br/lucasrguerra/pss.git
cd pss cd pss
# Install dependencies # Install dependencies
@@ -57,9 +57,36 @@ npm run preview
### With Docker ### With Docker
```bash ```bash
docker compose up docker compose up --build
``` ```
The `Dockerfile` builds Vite inside the image (Node 22) and serves the static files
with an unprivileged nginx (`nginx` user, port 8080). There is no pre-built artifact in the repository.
### Published image
Every version is published to the Gitea container registry (linux/arm64):
```bash
docker run -p 8080:8080 git.lucasrguerra.dev.br/lucasrguerra/pss:latest
```
Tags: `latest`, `X.Y.Z`, `X.Y` and `sha-<commit>`. The public instance runs at
[pss.lucasrguerra.dev.br](https://pss.lucasrguerra.dev.br).
### Continuous integration and releases
- `.gitea/workflows/ci.yml`: types (`tsc -b`), tests, Trivy (dependencies and secrets),
image build, Trivy on the image and a smoke test (the SPA responds, falls back to the
index on internal routes and serves assets with immutable caching). Runs on branches
and every Monday.
- `.gitea/workflows/release.yml`: on `main` and `vX.Y.Z` tags. If the registry already
has the image for the same content (`inputs-<hash>`), nothing is rebuilt: only the new
tags are applied. On a tag, it creates the Gitea release with the [CHANGELOG](CHANGELOG.md) notes.
- To release: update the CHANGELOG, the version in `package.json` and the label in
`src/components/Layout/Sidebar.tsx`, commit, and push the tag
(`git tag vX.Y.Z && git push gitea vX.Y.Z`).
--- ---
## 🎮 How to use ## 🎮 How to use
@@ -229,4 +256,4 @@ Contributions are welcome! Please read our [CONTRIBUTING.md](./CONTRIBUTING.md)
## 📜 License ## 📜 License
Distributed under the [MIT License](./LICENSE). Developed by [Lucas Rayan Guerra](https://github.com/lucasrguerra). Distributed under the [MIT License](./LICENSE). Developed by [Lucas Rayan Guerra](https://git.lucasrguerra.dev.br/lucasrguerra).
+30 -3
View File
@@ -33,7 +33,7 @@ Ideal para:
```bash ```bash
# Clone o repositório # Clone o repositório
git clone https://github.com/lucasrguerra/pss.git git clone https://git.lucasrguerra.dev.br/lucasrguerra/pss.git
cd pss cd pss
# Instale as dependências # Instale as dependências
@@ -55,9 +55,36 @@ npm run preview
### Com Docker ### Com Docker
```bash ```bash
docker compose up docker compose up --build
``` ```
O `Dockerfile` compila o Vite dentro da própria imagem (Node 22) e entrega os
arquivos estáticos por um nginx sem privilégios (usuário `nginx`, porta 8080). Não há artefato pré-construído no repositório.
### Imagem publicada
Cada versão é publicada no registro de contêineres do Gitea (linux/arm64):
```bash
docker run -p 8080:8080 git.lucasrguerra.dev.br/lucasrguerra/pss:latest
```
Tags: `latest`, `X.Y.Z`, `X.Y` e `sha-<commit>`. A instância pública roda em
[pss.lucasrguerra.dev.br](https://pss.lucasrguerra.dev.br).
### Integração contínua e releases
- `.gitea/workflows/ci.yml`: tipos (`tsc -b`), testes, Trivy (dependências e segredos),
build da imagem, Trivy na imagem e um teste de fumaça (a SPA responde, cai no index
nas rotas internas e entrega os assets com cache imutável). Roda nas branches e toda
segunda-feira.
- `.gitea/workflows/release.yml`: na `main` e nas tags `vX.Y.Z`. Se o registro já tem a
imagem do mesmo conteúdo (`inputs-<hash>`), nada é refeito: só as tags novas são
aplicadas. Numa tag, cria a release no Gitea com as notas do [CHANGELOG](CHANGELOG.md).
- Para lançar: atualize o CHANGELOG, a versão em `package.json` e o rótulo em
`src/components/Layout/Sidebar.tsx`, faça o commit e envie a tag
(`git tag vX.Y.Z && git push gitea vX.Y.Z`).
--- ---
## 🎮 Como usar ## 🎮 Como usar
@@ -227,4 +254,4 @@ Contribuições são bem-vindas! Por favor, consulte nosso guia em [CONTRIBUTING
## 📜 Licença ## 📜 Licença
Distribuído sob a [Licença MIT](./LICENSE). Desenvolvido por [Lucas Rayan Guerra](https://github.com/lucasrguerra). Distribuído sob a [Licença MIT](./LICENSE). Desenvolvido por [Lucas Rayan Guerra](https://git.lucasrguerra.dev.br/lucasrguerra).
BIN
View File
Binary file not shown.
+7 -1
View File
@@ -2,5 +2,11 @@ services:
pss: pss:
build: . build: .
ports: ports:
- "${PORT:-3000}:80" - "${PORT:-3000}:8080"
restart: unless-stopped restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:8080/ || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
+1 -1
View File
@@ -1,5 +1,5 @@
server { server {
listen 80; listen 8080;
server_name _; server_name _;
root /usr/share/nginx/html; root /usr/share/nginx/html;
index index.html; index index.html;
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "pss", "name": "pss",
"version": "1.2.0", "version": "1.3.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pss", "name": "pss",
"version": "1.2.0", "version": "1.3.3",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"clsx": "^2.1.1", "clsx": "^2.1.1",
+4 -5
View File
@@ -1,12 +1,11 @@
{ {
"name": "pss", "name": "pss",
"version": "1.3.2", "version": "1.3.3",
"description": "Process Scheduler Simulator — an interactive educational tool that runs entirely in the browser", "description": "Process Scheduler Simulator — an interactive educational tool that runs entirely in the browser",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "tsc -b && vite build", "build": "tsc -b && vite build",
"build:release": "tsc -b && vite build && tar --dereference -czf dist.tar.gz dist",
"preview": "vite preview", "preview": "vite preview",
"test": "vitest run", "test": "vitest run",
"test:watch": "vitest", "test:watch": "vitest",
@@ -39,14 +38,14 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/lucasrguerra/pss.git" "url": "git+https://git.lucasrguerra.dev.br/lucasrguerra/pss.git"
}, },
"keywords": [], "keywords": [],
"author": "Lucas Rayan Guerra", "author": "Lucas Rayan Guerra",
"license": "MIT", "license": "MIT",
"type": "commonjs", "type": "commonjs",
"bugs": { "bugs": {
"url": "https://github.com/lucasrguerra/pss/issues" "url": "https://git.lucasrguerra.dev.br/lucasrguerra/pss/issues"
}, },
"homepage": "https://github.com/lucasrguerra/pss#readme" "homepage": "https://git.lucasrguerra.dev.br/lucasrguerra/pss#readme"
} }
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Uso: scripts/plano-imagem.sh <registro> <repositório>
# Imprime inputs=, image= e reuse= (para $GITHUB_OUTPUT). O hash cobre só os
# arquivos que entram no build da imagem, não a documentação nem a configuração
# de ferramentas. reuse=true quando o registro já tem inputs-<hash>.
set -euo pipefail
registry=$1; ns=${2,,}
inputs=$(git ls-tree -r HEAD \
| awk -F'\t' '$2 !~ /^(\.gitea|\.github|\.claude|\.wolf|\.superset|docs)\// && $2 !~ /^(README.*|CONTRIBUTING\.md|CHANGELOG\.md|CITATION\.cff|LICENSE|paper\.md|references\.bib|\.gitignore|\.gitattributes|scripts\/release-notes\.sh)$/' \
| sha256sum | cut -c1-16)
token=$(curl -fsS "https://$registry/v2/token?service=container_registry&scope=repository:$ns:pull" | jq -r .token)
code=$(curl -s -o /dev/null -w '%{http_code}' -I \
-H "Authorization: Bearer $token" \
-H 'Accept: application/vnd.oci.image.index.v1+json,application/vnd.docker.distribution.manifest.list.v2+json,application/vnd.oci.image.manifest.v1+json' \
"https://$registry/v2/$ns/manifests/inputs-$inputs")
echo "inputs-$inputs -> HTTP $code" >&2
reuse=false; [ "$code" = 200 ] && reuse=true
echo "inputs=$inputs"
echo "image=$registry/$ns"
echo "reuse=$reuse"
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
# Imprime as notas de uma release: a imagem publicada (quando houver) e a seção
# do CHANGELOG.md daquela versão (ou o log de commits desde a tag anterior, se
# não houver seção).
#
# scripts/release-notes.sh v1.2.3 [git.exemplo.com/dono/projeto]
set -euo pipefail
tag=${1:?uso: release-notes.sh <tag> [imagem]}
image=${2:-}
version=${tag#v}
if [ -n "$image" ]; then
echo "## Imagem"
echo
echo '```'
echo "$image:$version"
echo '```'
echo
fi
section=""
if [ -f CHANGELOG.md ]; then
section=$(awk -v head="## [$version]" '
index($0, head) == 1 { found = 1; next }
found && /^## \[/ { exit }
found && /^\[[^]]+\]: / { next }
found { print }
' CHANGELOG.md)
fi
if [ -n "$(printf '%s' "$section" | tr -d '[:space:]')" ]; then
printf '%s\n' "$section"
else
previous=$(git describe --tags --abbrev=0 "$tag^" 2>/dev/null || true)
echo "## Mudanças${previous:+ desde $previous}"
echo
git log --no-merges --format='- %s (%h)' "${previous:+$previous..}$tag"
fi
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
# Teste de fumaça da imagem: a SPA serve o index, cai no index em rotas internas
# e entrega os assets com cache longo.
#
# scripts/smoke-imagem.sh http://127.0.0.1:3998
#
# Cada falha é impressa e o script sai com 1 no fim, para mostrar tudo de uma vez.
set -uo pipefail
base=${1:?uso: smoke-imagem.sh <url-base>}
falhas=0
falhou() { echo "FALHOU $1"; falhas=$((falhas + 1)); }
# O nginx leva um instante para subir.
for _ in $(seq 1 30); do curl -fsS -o /dev/null "$base/" 2>/dev/null && break; sleep 1; done
index=$(curl -fsS "$base/") || { echo "FALHOU /: sem resposta"; exit 1; }
grep -q 'id="root"' <<< "$index" || falhou "/: o index não tem o #root"
# Rota interna da SPA devolve o mesmo index (try_files), não 404.
[ "$(curl -s -o /dev/null -w '%{http_code}' "$base/qualquer/rota")" = 200 ] || falhou "/qualquer/rota: esperado 200"
# Todo asset que o index referencia existe e tem cache imutável.
assets=$(grep -oE '(src|href)="/assets/[^"]+"' <<< "$index" | cut -d'"' -f2)
[ -n "$assets" ] || falhou "o index não referencia nenhum /assets/"
for a in $assets; do
head=$(curl -sI "$base$a")
grep -q '^HTTP/[0-9.]* 200' <<< "$head" || falhou "$a: esperado 200"
grep -qi 'cache-control:.*immutable' <<< "$head" || falhou "$a: sem cache imutável"
done
[ "$falhas" = 0 ] && echo "ok: $(wc -w <<< "$assets") assets e rotas conferidos"
[ "$falhas" = 0 ]
+1 -1
View File
@@ -12,7 +12,7 @@ const Sidebar = () => {
</div> </div>
<div className="h-12 border-t border-slate-700 flex items-center justify-center text-xs text-slate-500"> <div className="h-12 border-t border-slate-700 flex items-center justify-center text-xs text-slate-500">
PSS v1.3.2 PSS v1.3.3
</div> </div>
</aside> </aside>
); );