Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ jobs:
package-manager-cache: false
- run: npm ci --ignore-scripts
- run: npm run check
- name: Set up the IDE project evaluation toolchain
if: runner.os == 'Windows'
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6
with:
dotnet-version: "10.0.401"
- name: Verify effective IDE project declarations
if: runner.os == 'Windows'
run: node tooling/project.ts licence-evaluated
- name: Retain project licence declarations
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: licence-evidence-${{ matrix.os }}-${{ github.run_id }}-${{ github.run_attempt }}
path: artifacts/evidence/licence-*.json
if-no-files-found: error
retention-days: 30

quality:
name: Dependency audit and repository checks
Expand Down
4 changes: 4 additions & 0 deletions ArcForges.Web.esproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@
<ShouldRunBuildScript>true</ShouldRunBuildScript>
<BuildOutputFolder>$(MSBuildProjectDirectory)\artifacts\candidate</BuildOutputFolder>
</PropertyGroup>
<PropertyGroup>
<LicenceBoundary>AGPL</LicenceBoundary>
<PackageLicenseExpression>AGPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
</Project>
23 changes: 23 additions & 0 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project>
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
<Target Name="ArcForgesGetLicenceBoundary" Returns="@(_ArcForgesLicenceDeclaration)">
<ItemGroup>
<_ArcForgesLicenceDeclaration Include="$(MSBuildProjectFullPath)">
<SpdxLicense>$(PackageLicenseExpression)</SpdxLicense>
<Boundary>$(LicenceBoundary)</Boundary>
</_ArcForgesLicenceDeclaration>
</ItemGroup>
</Target>
<Target Name="ArcForgesVerifyLicenceBoundary" BeforeTargets="PrepareForBuild;Build;Pack">
<Error Condition="'$(PackageLicenseExpression)' != 'AGPL-3.0-only' Or '$(LicenceBoundary)' != 'AGPL'"
Text="AFL001: This repository requires AGPL-3.0-only / AGPL project metadata." />
<Error Condition="'%(ProjectReference.Identity)' != '' And !$([System.String]::Copy('%(ProjectReference.FullPath)').StartsWith('$(MSBuildThisFileDirectory)'))"
Text="AFL002: Project references must remain inside the owning repository." />
<MSBuild Projects="@(ProjectReference)" Targets="ArcForgesGetLicenceBoundary"
RemoveProperties="LicenceBoundary;PackageLicenseExpression" Condition="'@(ProjectReference)' != ''">
<Output TaskParameter="TargetOutputs" ItemName="_ArcForgesReferencedLicence" />
</MSBuild>
<Error Condition="'$(LicenceBoundary)' == 'Apache' And '%(_ArcForgesReferencedLicence.Identity)' != '' And '%(_ArcForgesReferencedLicence.Boundary)' != 'Apache'"
Text="AFL003: Apache projects may reference only Apache first-party projects." />
</Target>
</Project>
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

React and TypeScript Web foundation for the ArcForges family. This first increment contains a public Hello World site, an interactive local greeting, shared UI, published Contracts consumption and an automated Cloudflare Workers Static Assets delivery pipeline.

It does not implement the planned Account/Chat application, authentication, payments or a C# backend. The `/hello/` greeting runs locally and sends no name to a server. A separate `/cloud-hello/` page prepares the published gRPC-Web Hello call for the future Cloud container; it currently reports unavailable until that service is deployed. Business authority remains in ArcForges Cloud.
It does not implement the planned Account/Chat application, authentication, payments or a C# backend. The `/hello/` greeting runs locally and sends no name to a server. A separate `/cloud-hello/` page uses the published gRPC-Web client to call the deployed Cloud container after the user clicks **Check connection**. Business authority remains in ArcForges Cloud.

## Start locally

Expand Down Expand Up @@ -46,10 +46,13 @@ PRs run source checks on Linux/Windows, dependency auditing/review, secret scann

The main-only GitHub `cloudflare` environment contains the account variable and deployment secret. The custom-domain binding is managed in Cloudflare; CI verifies that it belongs to this Worker before deploying. PR checks remain credential-free. See [deployment setup and recovery](docs/deploying.md) and [evidence](docs/validation.md).

Workers Static Assets supports this static React build directly. Frameworks that need request-time server code require a Workers-compatible adapter/runtime. This setup does not host C# or provide an API proxy. The future Cloud Worker will own the same-origin `/api/*` route and forward to its Native AOT container; see the [Hello integration boundary and remaining Cloud setup](docs/cloud-hello.md). See also the [official React guide](https://developers.cloudflare.com/workers/framework-guides/web-apps/react/) and [static assets guide](https://developers.cloudflare.com/workers/static-assets/get-started/).
Workers Static Assets supports this static React build directly. Frameworks that need request-time server code require a Workers-compatible adapter/runtime. This setup does not host C# or provide an API proxy. The Cloud Worker owns the same-origin `/api/*` route and forwards to its Native AOT container; see the [Hello integration boundary and Cloud ownership](docs/cloud-hello.md). See also the [official React guide](https://developers.cloudflare.com/workers/framework-guides/web-apps/react/) and [static assets guide](https://developers.cloudflare.com/workers/static-assets/get-started/).

## Contribute

The build and CI enforce the [project licence declarations](docs/licence-boundary.md)
across every npm workspace and the JavaScript IDE adapter.

Read [development](docs/development.md), [contributing](CONTRIBUTING.md), [security](SECURITY.md), [validation](docs/validation.md), and the [bootstrap plan](docs/bootstrap-plan.md).

The existing repository license is **AGPL-3.0-only**; see [LICENSE](LICENSE). Upstream Contracts and other dependencies retain their own licenses. The built site exposes the license, source link and generated third-party notices. See [third-party notices](THIRD_PARTY_NOTICES.md).
3 changes: 3 additions & 0 deletions apps/site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,8 @@
"react-dom": "19.3.0",
"react-router": "8.4.0",
"isbot": "5.2.2"
},
"arcforges": {
"licenceBoundary": "AGPL"
}
}
12 changes: 6 additions & 6 deletions docs/cloud-hello.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Connecting the future Cloud service
# Connecting the Cloud service

## Current Web behavior

`/hello/` remains local. `/cloud-hello/` uses the published Contracts client to send one fixed diagnostic greeting after the user clicks **Check connection**. It sends no user-entered name, account cookie, authorization header or Cloudflare management token. Requests have a ten-second deadline, are cancelled on navigation, and are never automatically retried. Only the expected server response is displayed as success.

No Cloud service is currently deployed by this repository. Until its API route exists, the static Worker rejects the Hello POST with 405 Method Not Allowed; a GET at that missing path returns 404. The page shows an unavailable response. No mock is deployed and no successful response is generated locally.
The Cloud repository deploys the API Worker and Native AOT container independently of Web. A public browser check on 2026-09-18 verified that this page sends no API request on load, then sends exactly one POST after the click and displays `Hello, ArcForges!` from the real service. That observation used Web commit `86d6fded796d060eb064125baca7db690bc65419` and Cloud commit `6554400c04817491fe68d5e6319434034c5dc356`; it is a diagnostic integration result, not acceptance of later product APIs. If the Cloud API route is absent, the static Worker rejects the Hello POST with 405 Method Not Allowed; a GET at that missing path returns 404. The page shows an unavailable response. No mock is deployed and no successful response is generated locally.

## Fixed integration boundary

Expand All @@ -21,20 +21,20 @@ No Cloud service is currently deployed by this repository. Until its API route e

The Web origin stays `https://arcforges.com`; CSP keeps `connect-src 'self'` and no cross-origin exception is needed. A later account/authenticated API must define its own session behavior; this anonymous diagnostic must not silently start forwarding credentials.

## Work owned by the future Cloud repository
## Responsibilities owned by the Cloud repository

1. Build and test the actual C# Native AOT Linux container implementing this published wire contract. Cloudflare currently requires a `linux/amd64` image. Validate its AOT build, startup, gRPC-Web response/trailer framing, and failure statuses; the existing Contracts HelloHost example alone is not AOT evidence.
2. Deploy its Cloud Worker and Container binding in the same Cloudflare account. Forward to the container through that binding, removing only the leading `/api` from the public path. Preserve request/response protobuf bytes and gRPC-Web content type, statuses and framed trailers. Do not convert the payload to ad-hoc JSON or forward back to the public API URL.
3. Attach **Worker route** `arcforges.com/api/*` to the Cloud Worker. Keep the apex **Custom Domain** attached to `arcforges-web`. A route runs ahead of that custom-domain origin. The API route needs no second DNS hostname, browser token, Web service binding or Web rebuild. Unknown API methods must return an API error/404 rather than Web HTML.
4. Keep the example explicitly bounded: only the Hello diagnostic, with input/resource limits and no model call, paid user operation or database mutation. Authentication, quotas and commercial APIs remain a separate product increment. Worker/Container account permissions and plan availability are configured when Cloud is implemented.
4. Keep the example explicitly bounded: only the Hello diagnostic, with input/resource limits and no model call, paid user operation or database mutation. Authentication, quotas and commercial APIs remain a separate product increment. Cloud owns the Worker/Container account permissions and required plan availability.
5. Cloud's deployment gate must invoke the **public same-origin method using the published client**, verify the expected protobuf reply, and verify both success and failure behavior. Then check the button in the deployed Web page. A container health endpoint, mocked fixture or Web deployment alone does not establish this chain.

This repository does not provision the missing Cloud Worker, container image, API route, billing plan or credentials.
Cloud owns provisioning the Worker, container image, API route, billing plan and deployment credentials.

## Evidence and recovery

`cloud-hello-fixture.spec.ts` intercepts the browser API request with explicitly labelled protobuf wire fixtures. It verifies the actual published client's request, unavailable response and recovery. It is excluded from live Web verification so mocked success cannot be reported as a real C# integration. Live Web tests check that the new page loads and sends nothing automatically.

Web delivery still verifies its assets and Web-owned public 404 behavior. Candidate-only tests verify that the static Worker cannot fake a successful API response; the live Web gate does not require Web HTML at `/api/*`, because Cloud will own those paths. Cloud owns the later API/container deployment and its independent real integration gate. Removing Cloud's API route restores the static Worker's rejection of that API request; the connection page reports failure instead of silently falling back to a local greeting.
Web delivery still verifies its assets and Web-owned public 404 behavior. Candidate-only tests verify that the static Worker cannot fake a successful API response; the live Web gate does not require Web HTML at `/api/*`, because Cloud owns those paths. Cloud owns API/container deployment and its independent real integration gate. Removing Cloud's API route restores the static Worker's rejection of that API request; the connection page reports failure instead of silently falling back to a local greeting.

References: [routes before a Custom Domain](https://developers.cloudflare.com/workers/configuration/routing/custom-domains/#interaction-with-routes), [Cloudflare Containers setup](https://developers.cloudflare.com/containers/get-started/).
27 changes: 27 additions & 0 deletions docs/licence-boundary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Project licence boundaries (WP00.02)

The [accepted Design profile](https://github.com/ArcForges/ArcForges-Design/blob/6ba885ad38dd71de532c74d7b69f439d01d19a0a/docs/architecture/01-solution-and-project-layout.md#41-project-declaration-and-verification-profile)
assigns Web's original code, tests and tooling to AGPL-3.0-only / AGPL.
`eng/policy/licence-boundary.json` enumerates every current project/build manifest.
The inventory check discovers tracked and nonignored files independently; changing
the policy cannot change the permitted repository assignment.

The existing `npm run check` and candidate build check effective npm declarations,
source declarations for every build scope, imported MSBuild properties, project
reference containment and locked first-party package ownership. Tests exercise
new projects, missing/inconsistent properties, imports, escaped references, npm
aliases, unknown transitive first-party packages and invalid Gradle declarations.
No adjacent repository is imported or built. Third-party licences and existing
candidate notices remain separately owned and enforced.

`node tooling/project.ts licence-evaluated` evaluates owned MSBuild projects in
Debug and Release and retains their actual properties and reference edges. Build
targets reject wrong effective values before build/pack. Source and evaluated
reports include the exact commit, dirty state, inventory and findings under
`artifacts/evidence/licence-*.json`; CI uploads the reports.

The three npm scopes and the JavaScript IDE adapter are covered. Windows CI evaluates the IDE adapter using .NET SDK 10.0.401; normal npm development remains independent of that optional IDE toolchain. The existing final static candidate and three-browser tests remain required, followed by exact-byte Cloudflare delivery and live browser verification.

These source/build-policy results do not establish product functionality or close
later commercial gates. Local candidate identity and fixture/runtime evidence are
recorded separately from the merged deployment and public release.
24 changes: 24 additions & 0 deletions eng/policy/licence-boundary.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"schemaVersion": 1,
"repository": "Web",
"spdxLicense": "AGPL-3.0-only",
"licenceBoundary": "AGPL",
"projects": [
{
"path": "ArcForges.Web.esproj",
"kind": "msbuild"
},
{
"path": "apps/site/package.json",
"kind": "npm"
},
{
"path": "package.json",
"kind": "npm"
},
{
"path": "packages/ui/package.json",
"kind": "npm"
}
]
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,8 @@
"vite": "8.3.0",
"vitest": "5.0.1",
"wrangler": "4.132.0"
},
"arcforges": {
"licenceBoundary": "AGPL"
}
}
3 changes: 3 additions & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@
"peerDependencies": {
"react": "19.3.0",
"react-dom": "19.3.0"
},
"arcforges": {
"licenceBoundary": "AGPL"
}
}
Loading
Loading