diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 00000000..84952f69 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# +# pre-commit: block proprietary source from entering this public repo. +# Enable with: git config core.hooksPath .githooks +# +# Checks only the staged (added/copied/modified) files for speed. +# POSIX bash 3.2 compatible (stock macOS). +set -euo pipefail + +repo_root="$(git rev-parse --show-toplevel)" +checker="$repo_root/scripts/check-proprietary-source.sh" + +if [ ! -f "$checker" ]; then + echo "pre-commit: $checker is missing — refusing to commit without the guard." >&2 + exit 1 +fi + +staged=() +while IFS= read -r f; do + [ -n "$f" ] && staged+=("$f") +done < <(git diff --cached --name-only --diff-filter=ACM) + +if [ "${#staged[@]}" -eq 0 ]; then + exit 0 +fi + +bash "$checker" "${staged[@]}" diff --git a/.githooks/pre-merge-commit b/.githooks/pre-merge-commit new file mode 100755 index 00000000..a7de72d8 --- /dev/null +++ b/.githooks/pre-merge-commit @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# +# pre-merge-commit: git does NOT run pre-commit for merge commits, so a +# `git merge` that brings in proprietary source would otherwise slip past the +# local guard entirely. This repo vendors third-party sources (unity-webview), +# which makes merging an upstream branch a routine operation — exactly the case +# that needs covering. Delegates to the same check as pre-commit. +# +# Enable with: git config core.hooksPath .githooks +set -euo pipefail + +exec bash "$(git rev-parse --show-toplevel)/.githooks/pre-commit" diff --git a/.github/workflows/no-proprietary-source.yml b/.github/workflows/no-proprietary-source.yml new file mode 100644 index 00000000..1353be75 --- /dev/null +++ b/.github/workflows/no-proprietary-source.yml @@ -0,0 +1,41 @@ +name: No proprietary source + +# Fail-closed gate: keeps native (Java/Kotlin) source, the private Gradle +# build system, and the private build pipeline out of this public repo. +# Native code ships only as compiled .aar / .unitypackage / .bundle artifacts. +# See scripts/check-proprietary-source.sh for the denylist and rationale. +# +# Runs on every push to ANY branch (the repo is public, so a pushed branch is +# world-visible even without a PR) and on every PR. + +on: + pull_request: + types: [opened, synchronize, reopened] + push: + branches: ['**'] + +jobs: + no-proprietary-source: + runs-on: ubuntu-latest + # Read-only gate: it only ever scans the tree, so it must not be able to + # write to it. Do not widen without a concrete reason. + permissions: + contents: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Scan tracked files for proprietary source + run: bash scripts/check-proprietary-source.sh + shell: bash + + - name: Reject submodule gitlinks + run: | + gitlinks=$(git ls-files -s | awk '$1 == "160000" { print $4 }') + if [ -n "$gitlinks" ]; then + echo "ERROR: submodule gitlink(s) found — the private repos must not be" >&2 + echo "referenced as submodules in this public repo:" >&2 + echo "$gitlinks" | sed 's/^/ - /' >&2 + exit 1 + fi + shell: bash diff --git a/.gitignore b/.gitignore index 1319889e..1500dd16 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,16 @@ obj/ ehthumbs.db Thumbs.db +# ============ # +# Backup / merge artifacts (defense-in-depth: keep proprietary source that +# leaks into *.orig/*.bak/*~ from being staged by `git add -A`). The guard +# in scripts/check-proprietary-source.sh is the enforced backstop. +# ============ # +*.orig +*.rej +*.bak +*~ + # ============ # # Visual Studio Code generated # # ============ # @@ -77,51 +87,9 @@ ai-setup-backup-*.tar.gz .serena/ .state/ .worktrees/ - -# framework-local state roots -.compound-engineering/* -!.compound-engineering/plans/ -!.compound-engineering/plans/** -!.compound-engineering/brainstorms/ -!.compound-engineering/brainstorms/** -!.compound-engineering/solutions/ -!.compound-engineering/solutions/** -!.compound-engineering/knowledge/ -!.compound-engineering/knowledge/** -!.compound-engineering/evidence/ -!.compound-engineering/evidence/** -!.compound-engineering/specs/ -!.compound-engineering/specs/** -!.compound-engineering/*.md -!.compound-engineering/*.example.yaml -.sisyphus/* -!.sisyphus/plans/ -!.sisyphus/plans/** -!.sisyphus/brainstorms/ -!.sisyphus/brainstorms/** -!.sisyphus/solutions/ -!.sisyphus/solutions/** -!.sisyphus/knowledge/ -!.sisyphus/knowledge/** -!.sisyphus/evidence/ -!.sisyphus/evidence/** -!.sisyphus/specs/ -!.sisyphus/specs/** -!.sisyphus/*.md -!.sisyphus/*.example.yaml -.planning/* -!.planning/plans/ -!.planning/plans/** -!.planning/brainstorms/ -!.planning/brainstorms/** -!.planning/solutions/ -!.planning/solutions/** -!.planning/knowledge/ -!.planning/knowledge/** -!.planning/evidence/ -!.planning/evidence/** -!.planning/specs/ -!.planning/specs/** -!.planning/*.md -!.planning/*.example.yaml -# END idream-managed agent workspace +.claude/worktrees/ +.claude/*.local.json +.omc/ +.compound-engineering/ +.sisyphus/ +.planning/ diff --git a/.serena/.gitignore b/.serena/.gitignore deleted file mode 100644 index 14d86ad6..00000000 --- a/.serena/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/cache diff --git a/.serena/memories/project_overview.md b/.serena/memories/project_overview.md deleted file mode 100644 index 411e2377..00000000 --- a/.serena/memories/project_overview.md +++ /dev/null @@ -1,6 +0,0 @@ -# Project Overview -- Purpose: Unity plugin providing a C# wrapper around the AirConsole JavaScript API so Unity developers can build local multiplayer games that communicate with the AirConsole backend through the embedded web/websocket server. -- Tech stack: Unity/C# scripts plus accompanying assets located primarily under `Assets/`. Targets AirConsole-supported platforms (WebGL and Android TV). -- Repo structure highlights: Unity project root with standard folders (`Assets`, `Packages`, `ProjectSettings`, etc.), csproj files for various Unity modules/tests, documentation PDF in `Assets/AirConsole/Documentation_1.7.pdf`, and changelog/README at root. -- Entry points: open the Unity project (`airconsole-unity-plugin.sln` or via Unity Hub) and use provided AirConsole scenes/examples under `Assets/AirConsole` as the starting point. -- Special notes: includes embedded webserver/websocket server for editor communication, so no extra server dependency is required. \ No newline at end of file diff --git a/.serena/memories/style_and_conventions.md b/.serena/memories/style_and_conventions.md deleted file mode 100644 index b79fa29b..00000000 --- a/.serena/memories/style_and_conventions.md +++ /dev/null @@ -1,4 +0,0 @@ -# Style and Conventions -- Code is written in standard Unity/C# style (PascalCase for classes/methods, camelCase for private fields, serialized fields attributed as needed). -- Project relies on Unity-specific patterns (MonoBehaviours, scriptable objects, etc.); follow Unity's serialization and inspector conventions when modifying scripts. -- No repository-specific linting or formatting rules were documented, so adhere to default C# conventions and Unity best practices. \ No newline at end of file diff --git a/.serena/memories/suggested_commands.md b/.serena/memories/suggested_commands.md deleted file mode 100644 index 015c78e8..00000000 --- a/.serena/memories/suggested_commands.md +++ /dev/null @@ -1,6 +0,0 @@ -# Suggested Commands -- `git status` / `git diff` – inspect working tree and patch content. -- `ls` / `find . -name "*.cs"` – explore repository contents on macOS (Darwin) shell. -- `open airconsole-unity-plugin.sln` or launch via Unity Hub to edit/run the Unity project. -- Use the Unity Test Runner inside the Unity Editor to execute EditMode/PlayMode tests (no standalone CLI documented). -- Refer to the embedded documentation PDF at `Assets/AirConsole/Documentation_1.7.pdf` for setup instructions. \ No newline at end of file diff --git a/.serena/memories/task_completion.md b/.serena/memories/task_completion.md deleted file mode 100644 index ccb983dd..00000000 --- a/.serena/memories/task_completion.md +++ /dev/null @@ -1,6 +0,0 @@ -# Task Completion Checklist -- Ensure changes build inside the Unity Editor and do not break the AirConsole example scenes. -- Run relevant Unity EditMode/PlayMode tests through the Unity Test Runner if scripts were modified. -- Update README/CHANGELOG or documentation PDF references if behavior changes. -- Verify WebGL/Android-specific behavior when applicable (e.g., platform messaging, webview debugging instructions). -- Commit with clear messages and keep the embedded webserver/websocket functionality intact. \ No newline at end of file diff --git a/.serena/project.yml b/.serena/project.yml deleted file mode 100644 index b58f439f..00000000 --- a/.serena/project.yml +++ /dev/null @@ -1,133 +0,0 @@ - - -# list of languages for which language servers are started; choose from: -# al angular ansible bash clojure -# cpp cpp_ccls crystal csharp csharp_omnisharp -# dart elixir elm erlang fortran -# fsharp go groovy haskell haxe -# hlsl html java json julia -# kotlin lean4 lua luau markdown -# matlab msl nix ocaml pascal -# perl php php_phpactor powershell python -# python_jedi python_ty r rego ruby -# ruby_solargraph rust scala scss solidity -# svelte swift systemverilog terraform toml -# typescript typescript_vts vue yaml zig -# (This list may be outdated. For the current list, see values of Language enum here: -# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py -# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.) -# Note: -# - For C, use cpp -# - For JavaScript, use typescript -# - For Angular projects, use angular (subsumes typescript+html; requires `npm install` in the project root) -# - For Svelte projects, use svelte (subsumes typescript/javascript for .svelte projects; requires npm) -# - For SCSS / Sass / plain CSS, use scss (some-sass-language-server handles all three) -# - For Free Pascal/Lazarus, use pascal -# Special requirements: -# Some languages require additional setup/installations. -# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers -# When using multiple languages, the first language server that supports a given file will be used for that file. -# The first language is the default language and the respective language server will be used as a fallback. -# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored. -languages: -- csharp - -# the encoding used by text files in the project -# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings -encoding: "utf-8" - -# whether to use project's .gitignore files to ignore files -ignore_all_files_in_gitignore: true - -# list of additional paths to ignore in this project. -# Same syntax as gitignore, so you can use * and **. -# Note: global ignored_paths from serena_config.yml are also applied additively. -ignored_paths: [] - -# whether the project is in read-only mode -# If set to true, all editing tools will be disabled and attempts to use them will result in an error -# Added on 2025-04-18 -read_only: false - -# list of tool names to exclude. -# This extends the existing exclusions (e.g. from the global configuration) -# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html -excluded_tools: [] - -# initial prompt for the project. It will always be given to the LLM upon activating the project -# (contrary to the memories, which are loaded on demand). -initial_prompt: "" -# the name by which the project can be referenced within Serena -project_name: "airconsole-unity-plugin" - -# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default). -# This extends the existing inclusions (e.g. from the global configuration). -# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html -included_optional_tools: [] - -# list of mode names that are to be activated by default, overriding the setting in the global configuration. -# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. -# If the setting is undefined/empty, the default_modes from the global configuration (serena_config.yml) apply. -# Otherwise, this overrides the setting from the global configuration (serena_config.yml). -# Therefore, you can set this to [] if you do not want the default modes defined in the global config to apply -# for this project. -# This setting can, in turn, be overridden by CLI parameters (--mode). -# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes -default_modes: - -# list of mode names to be activated additionally for this project, e.g. ["query-projects"] -# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. -# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes -added_modes: - -# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools. -# This cannot be combined with non-empty excluded_tools or included_optional_tools. -# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html -fixed_tools: [] - -# time budget (seconds) per tool call for the retrieval of additional symbol information -# such as docstrings or parameter information. -# This overrides the corresponding setting in the global configuration; see the documentation there. -# If null or missing, use the setting from the global configuration. -symbol_info_budget: - -# The language backend to use for this project. -# If not set, the global setting from serena_config.yml is used. -# Valid values: LSP, JetBrains -# Note: the backend is fixed at startup. If a project with a different backend -# is activated post-init, an error will be returned. -language_backend: - -# line ending convention to use when writing source files. -# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default) -# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings. -line_ending: - -# list of regex patterns which, when matched, mark a memory entry as read‑only. -# Extends the list from the global configuration, merging the two lists. -read_only_memory_patterns: [] - -# list of regex patterns for memories to completely ignore. -# Matching memories will not appear in list_memories or activate_project output -# and cannot be accessed via read_memory or write_memory. -# To access ignored memory files, use the read_file tool on the raw file path. -# Extends the list from the global configuration, merging the two lists. -# Example: ["_archive/.*", "_episodes/.*"] -ignored_memory_patterns: [] - -# advanced configuration option allowing to configure language server-specific options. -# Maps the language key to the options. -# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available. -# No documentation on options means no options are available. -ls_specific_settings: {} - -# list of additional workspace folder paths for cross-package reference support (e.g. in monorepos). -# Paths can be absolute or relative to the project root. -# Each folder is registered as an LSP workspace folder, enabling language servers to discover -# symbols and references across package boundaries. -# Currently supported for: TypeScript. -# Example: -# additional_workspace_folders: -# - ../sibling-package -# - ../shared-lib -additional_workspace_folders: [] diff --git a/AGENTS.md b/AGENTS.md index 60b19f01..956dcd65 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -93,6 +93,15 @@ Unity build: run from Unity Editor or configured Unity batchmode build. PostprocessBuild auto runs during Unity build. Export package: use Unity export package workflow for `.unitypackage`. Run tests: use Unity Test Runner for EditMode and PlayMode suites. +## PROPRIETARY-SOURCE GUARD +This repo is PUBLIC. AirConsole-authored native Android and webview source is PRIVATE and ships here only as compiled artifacts. +NEVER commit native source or the private build system: `*.java`, `*.kt`, Gradle files, `*.sh`/`Rakefile`/`*.rake` build scripts, `*.toml` version catalogs, `AndroidManifest.xml`, `src/main/res/`, `*.iml`/`.idea/` project files. +Only compiled artifacts (`.aar`, `.unitypackage`, `.bundle`) and glue (`.cs`, `.jslib`) belong here. The sole `.mm` exception is `Assets/AirConsole/unity-webview/Plugins/iOS/*.mm` — third-party upstream (GREE / Takahashi, zlib), public by licence. Never add AirConsole-authored native code as `.mm`. +`scripts/check-proprietary-source.sh` is the shared denylist check. +CI `.github/workflows/no-proprietary-source.yml` is the authoritative gate; it scans every push (any branch) and PR. +Enable the fast local pre-commit guard once per clone: `git config core.hooksPath .githooks`. +A path guard cannot see file contents: never paste native source into an accepted file (`.cs`, `.md`) either. + ## FORBIDDEN NEVER hardcode device IDs. NO platform specific code outside `plugins/`. diff --git a/scripts/check-proprietary-source.sh b/scripts/check-proprietary-source.sh new file mode 100755 index 00000000..a62ec4aa --- /dev/null +++ b/scripts/check-proprietary-source.sh @@ -0,0 +1,158 @@ +#!/usr/bin/env bash +# +# check-proprietary-source.sh +# +# Fail-closed guard that keeps AirConsole proprietary source out of this +# PUBLIC (open-source) repository. +# +# The native Android library (airconsole-unity-android-plugin) and the +# native webview build inputs (airconsole-unity-webview) are maintained in +# separate PRIVATE repositories. Only their COMPILED artifacts are allowed +# to ship here: +# +# - unityandroidlibrary.aar (Android native, compiled) +# - WebViewPlugin-*.aar.tmpl (webview native, compiled) +# - *.unitypackage / *.bundle (compiled) +# +# ONE EXCEPTION, already in the tree: Assets/AirConsole/unity-webview/Plugins/ +# iOS/*.mm is third-party upstream (GREE / Keijiro Takahashi, zlib licence) and +# is public by licence, not by mistake. That is why *.mm is not on the denylist. +# AirConsole-authored native code must NEVER be added as *.mm. +# +# Source languages (*.java, *.kt), the Gradle build system, and the private +# build pipeline (shell/Rake scripts, version catalogs) reveal the internal +# technology and MUST NOT be committed here. A leak is effectively +# irreversible once pushed (git history, forks, indexers), so this check +# blocks by default and only whitelists Unity's own boilerplate + the +# content-free files listed below. +# +# Each source pattern also matches a trailing backup/merge/rename suffix +# (e.g. Foo.java.orig, build.gradle.bak, Plugin.kt~, Foo.java.txt) because +# git merge/rebase (.orig/.rej) and editors (~/.bak) create sibling files +# that hold the full verbatim source. +# +# KNOWN LIMITATIONS (a path denylist cannot see file CONTENT): +# - Proprietary source hand-pasted into an accepted file (.md/.cs) is not +# detected. Deliberately renaming source to an accepted extension is not +# detected. Both are outside the ACCIDENTAL-leak threat model this guard +# targets (git add -A after copying a native dir keeps real extensions, +# which ARE blocked). If the native stack ever gains C/C++/NDK sources +# (*.c/*.cpp/*.h/*.aidl) or loose native libs, add them below. +# +# Usage: +# check-proprietary-source.sh [file ...] +# - with file arguments: checks exactly those paths (pre-commit hook) +# - with no arguments: checks every tracked file (CI full-tree scan) +# +# Exit status: 0 = clean, 1 = proprietary source found. +# +# POSIX bash 3.2 compatible (stock macOS) — no mapfile / associative arrays. + +set -euo pipefail + +# Suffix that may trail a source extension: end-of-path, or a '.' / '~' that +# begins a backup/merge/rename tail (.orig .bak .rej .txt .BACKUP.N, ~). +S='($|[.~])' + +# --- Denylist (parallel arrays; matched case-insensitively on the path) ------ +DENY_PATTERN=( + "\.(java|kt|kts)$S" + "\.gradle$S" + "\.pro$S" + "\.sh$S" + "\.toml$S" + "\.rake$S" + "(^|/)gradlew(\.bat)?$S" + "(^|/)gradle/wrapper/" + "(^|/)gradle\.properties$S" + "(^|/)Rakefile$S" + "(^|/)\.gitmodules$S" + "(^|/)AndroidManifest\.xml$S" + "(^|/)src/main/res/" + "\.iml$S" + "(^|/)\.idea/(modules|misc|gradle)\.xml$S" +) +DENY_REASON=( + 'native source (Java/Kotlin) — ships as a compiled .aar, never as source' + 'Gradle build script — reveals the private build setup' + 'ProGuard rules — reveal internal class structure' + 'shell build/install script — reveals the private build pipeline' + 'version catalog (.toml) — reveals the private dependency stack' + 'Rake build task — reveals the private build pipeline' + 'Gradle wrapper' + 'Gradle wrapper' + 'Gradle properties' + 'Ruby packaging build script — reveals the private build pipeline' + 'submodule reference — would disclose a private repository URL' + 'native Android manifest — declares internal components/permissions' + 'native Android resources — belong to the private library' + 'IntelliJ/Android Studio module file — reveals the private dependency stack' + 'IntelliJ/Android Studio project config — reveals the private module layout' +) + +# --- Allowlist: the ONLY exceptions to the denylist above -------------------- +# 1. Unity's own Android build templates (public boilerplate). +# 2. This guard script itself (the repo's own tooling). +# 3. *.meta — Unity import sidecars are content-free (GUID + import settings); +# they never contain source, so a Foo.java.meta / mainTemplate.gradle.meta +# is safe even though its base name trips a deny pattern. +ALLOW_PATTERN='(^|/)(mainTemplate|launcherTemplate|baseProjectTemplate|settingsTemplate)\.gradle$|(^|/)gradleTemplate\.properties$|(^|/)scripts/check-proprietary-source\.sh$|\.meta$' + +# --- Combined deny regex for one fast first-pass grep ------------------------ +combined="" +for p in "${DENY_PATTERN[@]}"; do + if [ -n "$combined" ]; then + combined="$combined|($p)" + else + combined="($p)" + fi +done + +# --- Emit the list of files to check ----------------------------------------- +list_files() { + if [ "$#" -gt 0 ]; then + printf '%s\n' "$@" + else + # No args → scan the whole tracked tree (CI standing invariant). + git ls-files + fi +} + +# --- reason_for : echo the denylist reason that matched ---------------- +reason_for() { + local path="$1" i + for i in "${!DENY_PATTERN[@]}"; do + if printf '%s' "$path" | grep -Eiq -- "${DENY_PATTERN[$i]}"; then + printf '%s' "${DENY_REASON[$i]}" + return + fi + done + printf '%s' 'proprietary source' +} + +violations=0 +while IFS= read -r path; do + [ -n "$path" ] || continue + # Skip explicitly allowlisted files. + if printf '%s' "$path" | grep -Eiq -- "$ALLOW_PATTERN"; then + continue + fi + if [ "$violations" -eq 0 ]; then + echo "ERROR: proprietary source must not be committed to this public repository." >&2 + echo >&2 + fi + printf ' \xe2\x9c\x97 %s\n -> %s\n' "$path" "$(reason_for "$path")" >&2 + violations=$((violations + 1)) +done < <(list_files "$@" | grep -Ei -- "$combined" || true) + +if [ "$violations" -gt 0 ]; then + echo >&2 + echo "Found $violations blocked file(s)." >&2 + echo "Native code lives in the private repos and ships here only as compiled" >&2 + echo "artifacts (.aar / .unitypackage / .bundle). Remove the source file(s) above." >&2 + echo "If a file is genuinely Unity boilerplate, add it to the ALLOW list in" >&2 + echo "scripts/check-proprietary-source.sh with justification." >&2 + exit 1 +fi + +exit 0