diff options
| author | Leitwolf | 2026-11-06 09:30:47 +0300 |
|---|---|---|
| committer | GitHub | 2026-11-06 09:30:47 +0300 |
| commit | fc3246f3eb404bc2c3132691d1161a95c5bfac76 (patch) | |
| tree | 1fa3e356b507113ba998767f8d550a8e3371bdbb | |
| parent | 9b4cc75dade5d9ab7e03284d52916bb2a6fddf36 (diff) | |
| parent | 1439b240a8231c5206e3c8d4f245493a076f2841 (diff) | |
| download | website-fc3246f3eb404bc2c3132691d1161a95c5bfac76.tar.gz | |
Merge pull request #54 from Progmasoft/ops/tazel-redirect
Redirect tazel.tala.run to tazel.net for good
| -rw-r--r-- | Documents/ARCHITECTURE.md | 10 | ||||
| -rw-r--r-- | Documents/OPERATIONS.md | 7 | ||||
| -rw-r--r-- | README.md | 5 | ||||
| -rw-r--r-- | frontend/tests/site-integrity.test.mjs | 28 | ||||
| -rw-r--r-- | ops/nginx/tala.conf | 58 |
5 files changed, 50 insertions, 58 deletions
diff --git a/Documents/ARCHITECTURE.md b/Documents/ARCHITECTURE.md index 2521b49..53a32ac 100644 --- a/Documents/ARCHITECTURE.md +++ b/Documents/ARCHITECTURE.md @@ -8,7 +8,7 @@ anything about a visitor on a server. | Part | Technology | Artifact | Serves | | --- | --- | --- | --- | -| `frontend/` | Vue 3, Vite, TypeScript | static files in `frontend/dist/` | `tala.run`, `talac.tala.run`, `tazel.tala.run` | +| `frontend/` | Vue 3, Vite, TypeScript | static files in `frontend/dist/` | `tala.run`, `talac.tala.run`, `talafmt.tala.run`, `talalint.tala.run` | | `backend/` | ASP.NET Core 10 | one published application | `tala.run/api/v1/site` | | `forum/` | one HTML page with plain CSS and JavaScript | the five files as they are | `forum.tala.run` | @@ -17,7 +17,8 @@ browser | HTTPS v Nginx - |-- tala.run, talac.tala.run, tazel.tala.run static files of the Vue build; unknown paths fall back to index.html + |-- tala.run, talac.tala.run, talafmt.tala.run, talalint.tala.run static files of the Vue build + |-- tazel.tala.run permanent redirects to tazel.net, Tazel's own site |-- tala.run/api/v1/site -> http://127.0.0.1:5086 (ASP.NET Core) |-- forum.tala.run five named static files; every other path is 404 |-- www.tala.run permanent redirect to tala.run @@ -36,7 +37,6 @@ A single-page application that serves three sites. `site.ts` decides the site fr | `tala.run` | `/docs/getting-started` | building the compiler from its repository | `pages/GettingStartedPage.vue` | | `tala.run` | `/docs/syntax` | a first look at the syntax | `content/syntax.ts` | | `talac.tala.run` | `/docs/command-line`, `/docs/outputs` | the compiler | `content/talac.ts` | -| `tazel.tala.run` | `/docs/commands`, `/docs/project-file` | the build system | `content/tazel.ts` | The pages from `content/` are rendered by `pages/DocPage.vue`; each topic carries its text in all four languages. The root of the two documentation hosts opens their first topic. Any other path redirects to the root. The router uses history URLs, so the server must answer unknown paths with @@ -92,8 +92,8 @@ allows only its own script, stylesheet and two images. ## Search engines and crawlers -- Each host has its own `sitemap.xml` and `robots.txt`; Nginx serves `public/hosts/talac/` and - `public/hosts/tazel/` for the two documentation hosts. A sitemap lists exactly the routes of its host. +- Each host has its own `sitemap.xml` and `robots.txt`; Nginx serves `public/hosts/<host>/` for the documentation + hosts. A sitemap lists exactly the routes of its host. - Every route has its own title, description and canonical URL. A language is a preference, not a second URL, so there are no `hreflang` alternatives. - `robots.txt` names the crawlers the site has a rule for. Search and answer-retrieval crawlers are allowed. Among diff --git a/Documents/OPERATIONS.md b/Documents/OPERATIONS.md index d77eb61..ce1a4ee 100644 --- a/Documents/OPERATIONS.md +++ b/Documents/OPERATIONS.md @@ -4,7 +4,8 @@ # Tala website operations This runbook covers only the language website, the documentation sites of the -compiler and the build system, and the not-yet-open forum page. +compiler, the formatter and the linter, the redirect of the build system's former +site, and the not-yet-open forum page. The account site, corporate site, and package service have their own repositories and deployments. A redirect from an old package hostname is retained for compatibility, but it does not make package functions part of this website. @@ -15,7 +16,7 @@ compatibility, but it does not make package functions part of this website. | --- | --- | --- | | `tala.run/`, `/docs/overview`, `/docs/getting-started`, `/docs/syntax` | Vue language site | Live | | `talac.tala.run/docs/*` | Vue build, compiler documentation | Live | -| `tazel.tala.run/docs/*` | Vue build, build-system documentation | Live | +| `tazel.tala.run/*` | Redirect | Permanent redirect to `tazel.net`, Tazel's own site: `/docs/commands` and `/docs/project-file` to `tazel.net/docs/reference/` with the same name, other `/docs/` paths to `tazel.net/docs`, the rest to the same path | | `tala.run/api/v1/site` | ASP.NET Core language API | Live; the only proxied API path | | `forum.tala.run/` | Static placeholder | Live; noindex | | `www.tala.run` | Redirect | Permanent redirect to `tala.run` | @@ -90,7 +91,7 @@ Before publication, verify that: All source links should target the current `Progmasoft/tala` default branch. In particular, check the `Spec/`, `Documents/BUILDING.md`, `Documents/CLI.md`, and `Examples/` targets after any repository move. -The routes of each site are listed in the route table above. A retired login, registration, or package route must +The routes of each site are listed in the route table above; tazel.tala.run answers each with a 308 to tazel.net. A retired login, registration, or package route must not reappear in the site shell. The forum placeholder links back to the language domain and to the compiler @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Gr # Tala website This repository owns the public language website at [tala.run](https://tala.run) and the documentation of the -compiler and the build system at [talac.tala.run](https://talac.tala.run) and [tazel.tala.run](https://tazel.tala.run). +compiler at [talac.tala.run](https://talac.tala.run). The build system has its own site, [tazel.net](https://tazel.net). It does not own Progmasoft's corporate or account sites. Tala uses its own supplied purple leopard SVG identity; the Progmasoft mark is a different brand. @@ -19,7 +19,8 @@ One frontend build serves three sites and picks its pages from the host name: explains the design direction, `tala.run/docs/getting-started` links the real compiler checkout and toolchain, and `tala.run/docs/syntax` gives a first look at the syntax from the public specification. - `talac.tala.run/docs/command-line` and `talac.tala.run/docs/outputs` document the compiler. -- `tazel.tala.run/docs/commands` and `tazel.tala.run/docs/project-file` document the build system. +- `tazel.tala.run` redirects permanently to [tazel.net](https://tazel.net); its two pages go to + `tazel.net/docs/reference/commands` and `tazel.net/docs/reference/project-file`. - `forum.tala.run` is a standalone informational page. It is *not* a forum service; accounts and posts do not exist there yet. It stays noindex until a real community forum is launched. diff --git a/frontend/tests/site-integrity.test.mjs b/frontend/tests/site-integrity.test.mjs index 4cce2ae..ba131f0 100644 --- a/frontend/tests/site-integrity.test.mjs +++ b/frontend/tests/site-integrity.test.mjs @@ -173,15 +173,14 @@ test("maintenance mode preserves the legacy redirect without opening the languag test("only the routes of the application get the app shell; other paths answer 404", () => { const live = readFileSync(join(websiteRoot, "ops/nginx/tala.conf"), "utf8"); assert.doesNotMatch(live, /try_files \$uri \$uri\/ \/index\.html;/); - assert.equal(live.match(/try_files \$uri \$uri\/ @application;/g)?.length, 5); - assert.equal(live.match(/error_page 404 \/index\.html;/g)?.length, 5); + assert.equal(live.match(/try_files \$uri \$uri\/ @application;/g)?.length, 4); + assert.equal(live.match(/error_page 404 \/index\.html;/g)?.length, 4); const patterns = [...live.matchAll(/if \(\$uri !~ "([^"]+)"\)/g)].map((match) => match[1]); assert.equal(new Set(patterns).size, 1, "every site must accept the same routes"); const route = new RegExp(patterns[0]); const pages = [ "public/sitemap.xml", "public/hosts/talac/sitemap.xml", - "public/hosts/tazel/sitemap.xml", "public/hosts/talafmt/sitemap.xml", "public/hosts/talalint/sitemap.xml", ] @@ -220,12 +219,33 @@ test("the former domain lands on the same path of tala.run and tala.run has no V /server_name forum\.xsharp-lang\.xyz;[^}]*return 308 https:\/\/forum\.tala\.run\$request_uri;/s, ); assert.doesNotMatch(live + forum, /viget\.tala\.run/); - for (const host of ["talac", "tazel", "talafmt", "talalint"]) { + for (const host of ["talac", "talafmt", "talalint"]) { assert.match(live, new RegExp(`try_files /hosts/${host}/robots\\.txt =404;`)); assert.match(live, new RegExp(`try_files /hosts/${host}/sitemap\\.xml =404;`)); } }); +test("tazel.tala.run only redirects to tazel.net, its two pages to their own", () => { + const live = readFileSync(join(websiteRoot, "ops/nginx/tala.conf"), "utf8").replaceAll( + "\r\n", + "\n", + ); + const start = live.indexOf( + "listen 443 ssl;\n listen [::]:443 ssl;\n http2 on;\n server_name tazel.tala.run;", + ); + assert.ok(start > 0, "tazel.tala.run has no HTTPS server"); + const server = live.slice(start, live.indexOf("\n}\n", start)); + assert.doesNotMatch(server, /\broot\b|try_files|hosts\/tazel/); + assert.match( + server, + /location ~ "\^\/docs\/\(commands\|project-file\)\/\?\$" \{\s*return 308 https:\/\/tazel\.net\/docs\/reference\/\$1\$is_args\$args;/, + ); + // A ^~ prefix would stop nginx before the regular expression above. + assert.match(server, /location \/docs\/ \{\s*return 308 https:\/\/tazel\.net\/docs;/); + assert.match(server, /location \/ \{\s*return 308 https:\/\/tazel\.net\$request_uri;/); + assert.match(server, /Strict-Transport-Security/); +}); + test("workflow actions are immutable and OIDC is isolated from build jobs", () => { const ci = readFileSync(join(websiteRoot, ".github/workflows/ci.yml"), "utf8"); const codeql = readFileSync(join(websiteRoot, ".github/workflows/codeql.yml"), "utf8"); diff --git a/ops/nginx/tala.conf b/ops/nginx/tala.conf index 3b0cadd..2b75fdd 100644 --- a/ops/nginx/tala.conf +++ b/ops/nginx/tala.conf @@ -1,11 +1,12 @@ # SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com> # SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 -# One frontend build serves five sites: tala.run for the language, -# talac.tala.run for the compiler, tazel.tala.run for the build system, -# talafmt.tala.run for the formatter and talalint.tala.run for the linter. -# The page picks its content from the host name. xsharp-lang.xyz, the former -# domain, answers with a permanent redirect to the same path on tala.run. +# One frontend build serves four sites: tala.run for the language, +# talac.tala.run for the compiler, talafmt.tala.run for the formatter and +# talalint.tala.run for the linter. The page picks its content from the host +# name. xsharp-lang.xyz, the former domain, answers with a permanent redirect to +# the same path on tala.run. tazel.tala.run, where the build system was +# documented, answers with a permanent redirect to tazel.net, its own site. server { listen 80 default_server; @@ -116,7 +117,7 @@ server { } } -# talac.tala.run, tazel.tala.run, talafmt.tala.run and talalint.tala.run serve +# talac.tala.run, talafmt.tala.run and talalint.tala.run serve # the same build; each answers for robots.txt and sitemap.xml with its own file. server { listen 443 ssl; @@ -303,9 +304,6 @@ server { listen [::]:443 ssl; http2 on; server_name tazel.tala.run; - - root /srv/xsharp/website/current/frontend; - index index.html; server_tokens off; ssl_certificate /etc/letsencrypt/live/tala.run/fullchain.pem; @@ -313,48 +311,20 @@ server { include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; - add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; object-src 'none'" always; - add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; - add_header X-Content-Type-Options "nosniff" always; - add_header X-Frame-Options "DENY" always; - - location = /robots.txt { - try_files /hosts/tazel/robots.txt =404; - } - location = /sitemap.xml { - try_files /hosts/tazel/sitemap.xml =404; + # The two pages of the old site have their own pages on tazel.net; any + # other page of its docs goes to the docs, everything else to the same path. + location ~ "^/docs/(commands|project-file)/?$" { + return 308 https://tazel.net/docs/reference/$1$is_args$args; } - location ^~ /hosts/ { - return 404; - } - - location ^~ /api/ { - return 404; + location /docs/ { + return 308 https://tazel.net/docs; } location / { - try_files $uri $uri/ @application; - } - - # The application has two kinds of routes: the landing page and - # /docs/<page>. Any other path that is not a file is answered with 404, so - # that unknown addresses, including the probes for /wp-login.php and - # friends, are not served as pages. The body of the 404 is still the - # application, whose router takes a visitor to the landing page. - location @application { - if ($uri !~ "^/(docs/[a-z0-9-]+/?)?$") { - return 404; - } - rewrite ^ /index.html break; - } - - error_page 404 /index.html; - - location ~ /\. { - deny all; + return 308 https://tazel.net$request_uri; } } |