Compare commits
3 Commits
d87aee80fa
...
feat/add-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
706f5f6dcc | ||
| f287fdf6d1 | |||
| 687c958bd1 |
@@ -15,7 +15,9 @@ WORKDIR /src
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY . .
|
||||
COPY --from=web-builder /web/dist/ web/dist/
|
||||
# Create placeholder files so //go:embed dist/* in web/embed.go resolves
|
||||
# without depending on the web-builder stage (lint should fail fast)
|
||||
RUN mkdir -p web/dist && touch web/dist/index.html web/dist/style.css web/dist/app.js
|
||||
RUN make fmt-check
|
||||
RUN make lint
|
||||
|
||||
|
||||
44
README.md
44
README.md
@@ -1374,14 +1374,16 @@ Return server metadata. No authentication required.
|
||||
```json
|
||||
{
|
||||
"name": "My NeoIRC Server",
|
||||
"version": "0.1.0",
|
||||
"motd": "Welcome! Be nice.",
|
||||
"users": 42
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Description |
|
||||
|---------|---------|-------------|
|
||||
|-----------|---------|-------------|
|
||||
| `name` | string | Server display name |
|
||||
| `version` | string | Server version |
|
||||
| `motd` | string | Message of the day |
|
||||
| `users` | integer | Number of currently active user sessions |
|
||||
|
||||
@@ -1850,26 +1852,16 @@ docker run -p 8080:8080 \
|
||||
neoirc
|
||||
```
|
||||
|
||||
The Dockerfile is a multi-stage build:
|
||||
1. **Build stage**: Compiles `neoircd` and `neoirc-cli` (CLI built to verify
|
||||
The Dockerfile is a four-stage build:
|
||||
1. **web-builder**: Installs Node dependencies and compiles the SPA (JSX →
|
||||
bundled JS via esbuild) into `web/dist/`
|
||||
2. **lint**: Runs formatting checks and golangci-lint against the Go source
|
||||
(uses empty placeholder files for `web/dist/` so it runs independently of
|
||||
web-builder for fast feedback)
|
||||
3. **builder**: Runs tests and compiles static `neoircd` and `neoirc-cli`
|
||||
binaries with the real SPA assets from web-builder (CLI built to verify
|
||||
compilation, not included in final image)
|
||||
2. **Final stage**: Alpine Linux + `neoircd` binary only
|
||||
|
||||
```dockerfile
|
||||
FROM golang:1.24-alpine AS builder
|
||||
WORKDIR /src
|
||||
RUN apk add --no-cache make
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY . .
|
||||
RUN go build -o /neoircd ./cmd/neoircd/
|
||||
RUN go build -o /neoirc-cli ./cmd/neoirc-cli/
|
||||
|
||||
FROM alpine:latest
|
||||
COPY --from=builder /neoircd /usr/local/bin/neoircd
|
||||
EXPOSE 8080
|
||||
CMD ["neoircd"]
|
||||
```
|
||||
4. **final**: Minimal Alpine image with only the `neoircd` binary
|
||||
|
||||
### Binary
|
||||
|
||||
@@ -2318,10 +2310,14 @@ neoirc/
|
||||
│ └── http.go # HTTP timeouts
|
||||
├── web/
|
||||
│ ├── embed.go # go:embed directive for SPA
|
||||
│ └── dist/ # Built SPA (vanilla JS, no build step)
|
||||
│ ├── index.html
|
||||
│ ├── style.css
|
||||
│ └── app.js
|
||||
│ ├── build.sh # SPA build script (esbuild, runs in Docker)
|
||||
│ ├── package.json # Node dependencies (preact, esbuild)
|
||||
│ ├── package-lock.json
|
||||
│ ├── src/ # SPA source files (JSX + HTML + CSS)
|
||||
│ │ ├── app.jsx
|
||||
│ │ ├── index.html
|
||||
│ │ └── style.css
|
||||
│ └── dist/ # Generated at Docker build time (not committed)
|
||||
├── schema/ # JSON Schema definitions (planned)
|
||||
├── go.mod
|
||||
├── go.sum
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Repository Policies
|
||||
last_modified: 2026-03-10
|
||||
last_modified: 2026-03-09
|
||||
---
|
||||
|
||||
This document covers repository structure, tooling, and workflow standards. Code
|
||||
@@ -92,20 +92,19 @@ style conventions are in separate documents:
|
||||
- Never commit secrets. `.env` files, credentials, API keys, and private keys
|
||||
must be in `.gitignore`. No exceptions.
|
||||
|
||||
- Build artifacts and code-derived data (compiled output, bundled JS, minified
|
||||
CSS, generated code) must NOT be committed to the repository if they can be
|
||||
generated during the build process. The Dockerfile or build system should
|
||||
produce these artifacts at build time. Notable exception: Go
|
||||
protobuf-generated files (`.pb.go`) may be committed because Go module
|
||||
consumers use `go get` which downloads source code but does not execute build
|
||||
steps.
|
||||
|
||||
- `.gitignore` should be comprehensive from the start: OS files (`.DS_Store`),
|
||||
editor files (`.swp`, `*~`), language build artifacts, and `node_modules/`.
|
||||
Fetch the standard `.gitignore` from
|
||||
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitignore` when setting up
|
||||
a new repo.
|
||||
|
||||
- **No build artifacts in version control.** Code-derived data (compiled
|
||||
bundles, minified output, generated assets) must never be committed to the
|
||||
repository if it can be avoided. The build process (e.g. Dockerfile, Makefile)
|
||||
should generate these at build time. Notable exception: Go protobuf generated
|
||||
files (`.pb.go`) ARE committed because repos need to work with `go get`, which
|
||||
downloads code but does not execute code generation.
|
||||
|
||||
- Never use `git add -A` or `git add .`. Always stage files explicitly by name.
|
||||
|
||||
- Never force-push to `main`.
|
||||
|
||||
@@ -2393,6 +2393,7 @@ func (hdlr *Handlers) HandleServerInfo() http.HandlerFunc {
|
||||
|
||||
hdlr.respondJSON(writer, request, map[string]any{
|
||||
"name": hdlr.params.Config.ServerName,
|
||||
"version": hdlr.params.Globals.Version,
|
||||
"motd": hdlr.params.Config.MOTD,
|
||||
"users": users,
|
||||
}, http.StatusOK)
|
||||
|
||||
@@ -16,6 +16,11 @@ import (
|
||||
|
||||
const routeTimeout = 60 * time.Second
|
||||
|
||||
// cspHeader is the Content-Security-Policy applied to the embedded web SPA.
|
||||
// The SPA loads external scripts and stylesheets from the same origin only;
|
||||
// all API communication uses same-origin fetch (no WebSockets).
|
||||
const cspHeader = "default-src 'self'; script-src 'self'; style-src 'self'"
|
||||
|
||||
// SetupRoutes configures the HTTP routes and middleware.
|
||||
func (srv *Server) SetupRoutes() {
|
||||
srv.router = chi.NewRouter()
|
||||
@@ -133,6 +138,11 @@ func (srv *Server) setupSPA() {
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
) {
|
||||
writer.Header().Set(
|
||||
"Content-Security-Policy",
|
||||
cspHeader,
|
||||
)
|
||||
|
||||
readFS, ok := distFS.(fs.ReadFileFS)
|
||||
if !ok {
|
||||
fileServer.ServeHTTP(writer, request)
|
||||
|
||||
Reference in New Issue
Block a user