@kavtuai/guildgate 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/LICENSE +21 -0
  3. package/README.md +399 -0
  4. package/README.tr.md +397 -0
  5. package/SECURITY.md +36 -0
  6. package/TEST_REPORT.md +50 -0
  7. package/bin/guildgate-doctor.mjs +91 -0
  8. package/bin/guildgate-writing-check.mjs +73 -0
  9. package/dist/action.d.ts +65 -0
  10. package/dist/action.d.ts.map +1 -0
  11. package/dist/action.js +4 -0
  12. package/dist/action.js.map +1 -0
  13. package/dist/cache.d.ts +23 -0
  14. package/dist/cache.d.ts.map +1 -0
  15. package/dist/cache.js +53 -0
  16. package/dist/cache.js.map +1 -0
  17. package/dist/crypto.d.ts +15 -0
  18. package/dist/crypto.d.ts.map +1 -0
  19. package/dist/crypto.js +87 -0
  20. package/dist/crypto.js.map +1 -0
  21. package/dist/discord/authorizer.d.ts +41 -0
  22. package/dist/discord/authorizer.d.ts.map +1 -0
  23. package/dist/discord/authorizer.js +101 -0
  24. package/dist/discord/authorizer.js.map +1 -0
  25. package/dist/discord/oauth.d.ts +64 -0
  26. package/dist/discord/oauth.d.ts.map +1 -0
  27. package/dist/discord/oauth.js +226 -0
  28. package/dist/discord/oauth.js.map +1 -0
  29. package/dist/discord/permissions.d.ts +85 -0
  30. package/dist/discord/permissions.d.ts.map +1 -0
  31. package/dist/discord/permissions.js +99 -0
  32. package/dist/discord/permissions.js.map +1 -0
  33. package/dist/discord.d.ts +4 -0
  34. package/dist/discord.d.ts.map +1 -0
  35. package/dist/discord.js +4 -0
  36. package/dist/discord.js.map +1 -0
  37. package/dist/errors.d.ts +43 -0
  38. package/dist/errors.d.ts.map +1 -0
  39. package/dist/errors.js +57 -0
  40. package/dist/errors.js.map +1 -0
  41. package/dist/express.d.ts +3 -0
  42. package/dist/express.d.ts.map +1 -0
  43. package/dist/express.js +3 -0
  44. package/dist/express.js.map +1 -0
  45. package/dist/fastify.d.ts +3 -0
  46. package/dist/fastify.d.ts.map +1 -0
  47. package/dist/fastify.js +3 -0
  48. package/dist/fastify.js.map +1 -0
  49. package/dist/http/express.d.ts +24 -0
  50. package/dist/http/express.d.ts.map +1 -0
  51. package/dist/http/express.js +60 -0
  52. package/dist/http/express.js.map +1 -0
  53. package/dist/http/fastify.d.ts +25 -0
  54. package/dist/http/fastify.d.ts.map +1 -0
  55. package/dist/http/fastify.js +57 -0
  56. package/dist/http/fastify.js.map +1 -0
  57. package/dist/i18n.d.ts +5 -0
  58. package/dist/i18n.d.ts.map +1 -0
  59. package/dist/i18n.js +66 -0
  60. package/dist/i18n.js.map +1 -0
  61. package/dist/index.d.ts +13 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +13 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/kernel.d.ts +83 -0
  66. package/dist/kernel.d.ts.map +1 -0
  67. package/dist/kernel.js +395 -0
  68. package/dist/kernel.js.map +1 -0
  69. package/dist/memory-store.d.ts +13 -0
  70. package/dist/memory-store.d.ts.map +1 -0
  71. package/dist/memory-store.js +261 -0
  72. package/dist/memory-store.js.map +1 -0
  73. package/dist/realtime/hub.d.ts +42 -0
  74. package/dist/realtime/hub.d.ts.map +1 -0
  75. package/dist/realtime/hub.js +152 -0
  76. package/dist/realtime/hub.js.map +1 -0
  77. package/dist/realtime/outbox.d.ts +12 -0
  78. package/dist/realtime/outbox.d.ts.map +1 -0
  79. package/dist/realtime/outbox.js +18 -0
  80. package/dist/realtime/outbox.js.map +1 -0
  81. package/dist/realtime.d.ts +3 -0
  82. package/dist/realtime.d.ts.map +1 -0
  83. package/dist/realtime.js +3 -0
  84. package/dist/realtime.js.map +1 -0
  85. package/dist/redis.d.ts +49 -0
  86. package/dist/redis.d.ts.map +1 -0
  87. package/dist/redis.js +233 -0
  88. package/dist/redis.js.map +1 -0
  89. package/dist/resilience.d.ts +23 -0
  90. package/dist/resilience.d.ts.map +1 -0
  91. package/dist/resilience.js +85 -0
  92. package/dist/resilience.js.map +1 -0
  93. package/dist/security.d.ts +21 -0
  94. package/dist/security.d.ts.map +1 -0
  95. package/dist/security.js +94 -0
  96. package/dist/security.js.map +1 -0
  97. package/dist/session.d.ts +32 -0
  98. package/dist/session.d.ts.map +1 -0
  99. package/dist/session.js +97 -0
  100. package/dist/session.js.map +1 -0
  101. package/dist/stores.d.ts +73 -0
  102. package/dist/stores.d.ts.map +1 -0
  103. package/dist/stores.js +4 -0
  104. package/dist/stores.js.map +1 -0
  105. package/dist/testing.d.ts +32 -0
  106. package/dist/testing.d.ts.map +1 -0
  107. package/dist/testing.js +60 -0
  108. package/dist/testing.js.map +1 -0
  109. package/dist/types.d.ts +183 -0
  110. package/dist/types.d.ts.map +1 -0
  111. package/dist/types.js +4 -0
  112. package/dist/types.js.map +1 -0
  113. package/docs/WRITING_STYLE.md +118 -0
  114. package/docs/architecture.md +83 -0
  115. package/docs/custom-stores.md +111 -0
  116. package/docs/owner-management.md +44 -0
  117. package/docs/research-notes.md +61 -0
  118. package/docs/setup.md +104 -0
  119. package/docs/threat-model.md +79 -0
  120. package/docs/tr/arastirma-notlari.md +41 -0
  121. package/docs/tr/guvenlik-bildirimi.md +7 -0
  122. package/docs/tr/kurulum.md +63 -0
  123. package/docs/tr/mimari.md +59 -0
  124. package/docs/tr/sahip-yonetimi.md +7 -0
  125. package/docs/tr/tehdit-modeli.md +39 -0
  126. package/docs/tr/veritabani-suruculeri.md +23 -0
  127. package/docs/tr/yazim-kilavuzu.md +116 -0
  128. package/docs/uml/action-sequence.mmd +39 -0
  129. package/docs/uml/components.mmd +84 -0
  130. package/docs/uml/deployment.mmd +19 -0
  131. package/docs/uml/oauth-sequence.mmd +30 -0
  132. package/docs/uml/realtime-sequence.mmd +28 -0
  133. package/package.json +90 -0
@@ -0,0 +1,111 @@
1
+ # Custom storage drivers
2
+
3
+ GuildGate does not select a database. Implement the interfaces in `GuildGateStores` and pass them to `createGuildGate()`.
4
+
5
+ ## Record placement
6
+
7
+ A common production layout is:
8
+
9
+ | Record | Suggested storage | Reason |
10
+ |---|---|---|
11
+ | Sessions | Redis or a database with expiry cleanup | Fast lookup and revocation |
12
+ | OAuth state | Redis or an atomic database record | Single-use consume operation |
13
+ | OAuth credentials | Durable database | Encrypted refresh tokens must survive restarts |
14
+ | Rate limits | Redis or another atomic counter store | Shared limits across instances |
15
+ | Cache | Redis or application cache | Shared invalidation |
16
+ | Idempotency | Redis or durable database | Atomic first-writer ownership |
17
+ | Locks | Redis, database advisory locks, or lease service | Shared resource exclusion |
18
+ | Audit | Durable append-oriented database | Search, retention, incident review |
19
+ | Outbox | Same database as the domain write when possible | Commit and delivery coordination |
20
+ | Policies | Durable database | Maintenance and block state survives restart |
21
+
22
+ This is a deployment suggestion, not a package requirement.
23
+
24
+ ## Required semantics
25
+
26
+ ### SessionStore
27
+
28
+ `set()` must replace the complete record. `listByUser()` must return active and revoked records still present in storage. The session manager removes expired records and enforces the per-user cap.
29
+
30
+ Do not store the raw session token. The core sends only `idHash` to the store.
31
+
32
+ ### OAuthStateStore
33
+
34
+ `consume(stateHash, nowIso)` must read and delete in one atomic operation. Two callbacks using the same state must not both succeed.
35
+
36
+ ### OAuthCredentialStore
37
+
38
+ Store only ciphertext produced by `TokenCipher`. Restrict direct database access because a stolen encryption key and copied ciphertext together expose Discord credentials.
39
+
40
+ ### RateLimitStore
41
+
42
+ `hit()` must atomically decide whether the cost fits within the current window. It returns the limit, remaining count, reset time, and retry delay.
43
+
44
+ A read followed by a write without a transaction is not sufficient for multiple instances.
45
+
46
+ ### CacheStore
47
+
48
+ `deleteByTags()` must delete entries matching any requested tag. It may return an approximate count if the backing cache expires index entries independently, but it must not leave known matching entries intentionally.
49
+
50
+ ### IdempotencyStore
51
+
52
+ `begin()` is a first-writer operation:
53
+
54
+ - No record: write `inflight` and return `started`.
55
+ - Same key and same request hash, still inflight: return `inflight`.
56
+ - Same key and same request hash, completed: return the stored response.
57
+ - Same key and different request hash: return `conflict`.
58
+
59
+ `complete()` must preserve the original request hash and store the result. `fail()` removes an abandoned reservation so a later retry can run.
60
+
61
+ ### LockStore
62
+
63
+ `acquire()` writes a lease only when no valid lease exists. `release()` must compare the token before deleting the lease. Deleting a lock by key alone can release a newer owner’s lock.
64
+
65
+ Long operations should renew leases or use a driver whose transaction lock lasts for the operation. GuildGate 0.1.0 does not include lease renewal.
66
+
67
+ ### AuditStore
68
+
69
+ Prefer append-only permissions for the application account. Redaction in the kernel covers known secret field names, but applications should avoid sending secrets in `changes` at all.
70
+
71
+ ### OutboxStore
72
+
73
+ `next()` returns unpublished rows. Multiple workers need row claiming, skip-locked reads, or another lease mechanism in the custom driver. `markPublished()` must be idempotent.
74
+
75
+ ### PolicyStore
76
+
77
+ Block lookup must ignore or remove expired blocks. `bumpPolicyVersion()` must be atomic. The version is written into audit events so an operator can see which policy generation handled a request.
78
+
79
+ ## Driver package layout
80
+
81
+ A separate adapter can be published without changing the core package:
82
+
83
+ ```text
84
+ packages/
85
+ guildgate-postgres/
86
+ src/
87
+ sessions.ts
88
+ credentials.ts
89
+ audit.ts
90
+ outbox.ts
91
+ policies.ts
92
+ index.ts
93
+ ```
94
+
95
+ Use peer dependencies for the ORM or database client when the adapter should share the application’s installed client.
96
+
97
+ ## Driver contract tests
98
+
99
+ Run the same behavior tests against every adapter:
100
+
101
+ - OAuth state can be consumed once under concurrency.
102
+ - A session can be revoked immediately.
103
+ - Rate costs never exceed the limit under parallel requests.
104
+ - One idempotency key has one owner.
105
+ - A changed payload causes a conflict.
106
+ - A lock cannot be released by another token.
107
+ - Tag invalidation removes all matching cache entries.
108
+ - Two outbox workers do not publish one row twice without an idempotent publisher.
109
+ - Expired blocks stop applying.
110
+
111
+ The repository’s memory driver is a reference for behavior, not for production durability.
@@ -0,0 +1,44 @@
1
+ # Owner management routes
2
+
3
+ Kernel owner methods are internal application APIs. They do not inspect an HTTP request by themselves. Expose them only through actions that require an owner session.
4
+
5
+ ```ts
6
+ const setMaintenance = gate.action({
7
+ name: "owner.maintenance.set",
8
+ parse(value) {
9
+ const body = value as Record<string, unknown>;
10
+ if (typeof body.enabled !== "boolean") throw new Error("enabled is required");
11
+ return {
12
+ enabled: body.enabled,
13
+ reason: typeof body.reason === "string" ? body.reason : undefined,
14
+ };
15
+ },
16
+ resource: () => ({ type: "policy", id: "maintenance" }),
17
+ rateLimit: { limit: 5, windowMs: 60_000 },
18
+ idempotency: { ttlMs: 10 * 60_000 },
19
+ authorize: (context) => ({
20
+ allowed: context.isOwner,
21
+ code: context.isOwner ? undefined : "GUILD_ACCESS_DENIED",
22
+ }),
23
+ async execute(_context, input) {
24
+ await gate.owner.setMaintenance({
25
+ enabled: input.enabled,
26
+ reason: input.reason,
27
+ allowOwners: true,
28
+ });
29
+ return { enabled: input.enabled };
30
+ },
31
+ audit: { changes: (result) => result },
32
+ });
33
+ ```
34
+
35
+ Use the same structure for user, guild, or IP blocks and for session revocation. Keep the actor, reason, affected subject, and policy version in audit records.
36
+
37
+ A read-only owner page can use:
38
+
39
+ ```ts
40
+ const sessions = await gate.sessions.list(userId);
41
+ const auditRows = await gate.config.stores.audit.list?.({ userId, limit: 100 });
42
+ ```
43
+
44
+ Do not return session hashes, OAuth ciphertext, raw IP values, or internal exception stacks to the browser.
@@ -0,0 +1,61 @@
1
+ # Research notes
2
+
3
+ Reviewed on 25 July 2026.
4
+
5
+ ## Writing review
6
+
7
+ Wikipedia’s “Signs of AI writing” page is an editing essay, not a conclusive detector. It groups possible signs under content, vocabulary and grammar, formatting, user-directed boilerplate, markup artifacts, citation faults, edit summaries, and older model behaviors.
8
+
9
+ GuildGate applies that material in two places:
10
+
11
+ - `docs/WRITING_STYLE.md` contains the full repository checklist in project terms.
12
+ - `guildgate-writing-check` rejects common assistant boilerplate, internal citation artifacts, tracking query strings, unfinished placeholders, and a selected list of vague promotional words outside the checklist itself.
13
+
14
+ Source: https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing
15
+
16
+ ## Discord OAuth and guild access
17
+
18
+ The Discord OAuth authorization-code flow supports a `state` value and Discord recommends it for request integrity. GuildGate hashes a one-time state record and binds it to a separate browser nonce cookie. The callback consumes the state once.
19
+
20
+ The default scopes are `identify` and `guilds`. The first identifies the signed-in user. The second returns the user’s guild list and guild permission value.
21
+
22
+ Discord permission values are serialized as strings because the bitfield can exceed safe JavaScript number precision. GuildGate parses them with `BigInt` and keeps user and bot permission checks separate.
23
+
24
+ Sources:
25
+
26
+ - https://docs.discord.com/developers/topics/oauth2
27
+ - https://docs.discord.com/developers/resources/user#get-current-user-guilds
28
+ - https://docs.discord.com/developers/topics/permissions
29
+
30
+ ## HTTP and session controls
31
+
32
+ OWASP session guidance recommends meaningless session identifiers with server-side state. GuildGate returns a random opaque token once and stores only its SHA-256 hash.
33
+
34
+ Cookie-authenticated write requests are exposed to cross-site request forgery. GuildGate requires an exact allowed origin and a session-bound CSRF token for unsafe methods.
35
+
36
+ Sources:
37
+
38
+ - https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html
39
+ - https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html
40
+
41
+ ## WebSocket controls
42
+
43
+ OWASP WebSocket guidance calls for origin validation, session handling beyond the initial handshake, authorization for individual messages or actions, payload limits, and logging without secret content.
44
+
45
+ GuildGate validates the origin and session at attach time, rechecks the session on a timer, authorizes each subscription, limits messages and subscriptions, and closes slow or expired connections.
46
+
47
+ Source: https://cheatsheetseries.owasp.org/cheatsheets/WebSocket_Security_Cheat_Sheet.html
48
+
49
+ ## Rate limits and retries
50
+
51
+ Discord applies route and global HTTP rate limits and returns response data that clients must respect. GuildGate’s inbound dashboard limits are separate from Discord’s outbound limits. The OAuth client honors `retry_after` under one total deadline. The guild authorizer surfaces a Discord 429 as a typed rate-limit error. Applications already using a Discord library REST manager should reuse that manager for broader bot traffic.
52
+
53
+ Source: https://docs.discord.com/developers/topics/rate-limits
54
+
55
+ ## npm publishing
56
+
57
+ npm trusted publishing uses OIDC from a supported CI provider instead of a long-lived npm publishing token. Current npm documentation also describes automatic provenance for supported trusted-publishing workflows.
58
+
59
+ The included release workflow grants `id-token: write`, runs tests, and publishes on a GitHub release. The npm package page must first be configured to trust the repository and workflow.
60
+
61
+ Source: https://docs.npmjs.com/trusted-publishers
package/docs/setup.md ADDED
@@ -0,0 +1,104 @@
1
+ # Setup and first release
2
+
3
+ ## 1. Prepare the repository
4
+
5
+ ```bash
6
+ unzip guildgate-0.1.0.zip
7
+ cd guildgate-0.1.0
8
+ npm install
9
+ npm test
10
+ ```
11
+
12
+ `npm install` creates `package-lock.json` on the first connected development machine. Commit that lockfile before the first pull request so CI and contributors install the same dependency graph.
13
+
14
+ ## 2. Run the deployment check
15
+
16
+ Copy `.env.example` to a private local environment file and fill the values. Generate separate random values for each secret.
17
+
18
+ ```bash
19
+ node ./bin/guildgate-doctor.mjs
20
+ ```
21
+
22
+ Use `GUILDGATE_ENVIRONMENT=production` for the final check. Production mode verifies HTTPS, the origin allowlist, secret lengths, and the token encryption key format.
23
+
24
+ ## 3. Create the GitHub repository
25
+
26
+ Create an empty public repository named `guildgate` under the `kavtuai` account. Do not add a remote README or license because the archive already contains both.
27
+
28
+ ```bash
29
+ git init
30
+ git branch -M main
31
+ git add .
32
+ git commit -m "feat: initial GuildGate release"
33
+ git remote add origin git@github.com:kavtuai/guildgate.git
34
+ git push -u origin main
35
+ ```
36
+
37
+ Enable these repository settings:
38
+
39
+ - Branch protection for `main`.
40
+ - Required CI and CodeQL checks.
41
+ - Pull-request review before merge.
42
+ - Secret scanning and push protection where available.
43
+ - Private vulnerability reporting.
44
+ - Dependabot alerts and security updates.
45
+
46
+ ## 4. Reserve and configure the npm package
47
+
48
+ The package name in `package.json` is `@kavtuai/guildgate`. The `kavtuai` npm organization or user scope must exist and permit public scoped packages.
49
+
50
+ Configure npm trusted publishing for this repository and the `.github/workflows/publish.yml` workflow. The workflow uses GitHub OIDC and does not need a long-lived npm token when trusted publishing is active.
51
+
52
+ Before release:
53
+
54
+ ```bash
55
+ npm login
56
+ npm whoami
57
+ npm run pack:check
58
+ ```
59
+
60
+ `npm pack --dry-run` shows the exact files that npm will receive.
61
+
62
+ ## 5. Publish through a GitHub release
63
+
64
+ Update `CHANGELOG.md`, commit the version, and create a signed or protected tag:
65
+
66
+ ```bash
67
+ npm version 0.1.0 --no-git-tag-version
68
+ git add package.json package-lock.json CHANGELOG.md
69
+ git commit -m "release: v0.1.0"
70
+ git tag -s v0.1.0 -m "GuildGate 0.1.0"
71
+ git push origin main v0.1.0
72
+ ```
73
+
74
+ Create a GitHub release from `v0.1.0`. The publish workflow runs tests and then sends the package to npm.
75
+
76
+ Do not publish from a workstation after trusted publishing is configured unless an incident procedure explicitly requires it.
77
+
78
+ ## 6. Test an installed package
79
+
80
+ Create a separate empty directory:
81
+
82
+ ```bash
83
+ mkdir guildgate-consumer-test
84
+ cd guildgate-consumer-test
85
+ npm init -y
86
+ npm install @kavtuai/guildgate@0.1.0
87
+ node -e "import('@kavtuai/guildgate').then(m => console.log(typeof m.createGuildGate))"
88
+ ```
89
+
90
+ The command should print `function`.
91
+
92
+ ## 7. First application integration
93
+
94
+ Use this order:
95
+
96
+ 1. Select durable and short-lived stores.
97
+ 2. Configure the kernel and run the doctor command.
98
+ 3. Add Discord OAuth start and callback routes.
99
+ 4. Add a session bootstrap endpoint that returns the CSRF token to the signed-in frontend.
100
+ 5. Add one read action and one idempotent write action.
101
+ 6. Add live guild authorization to the write action.
102
+ 7. Add audit and outbox retention jobs.
103
+ 8. Connect the realtime hub only after HTTP authorization works.
104
+ 9. Test role removal, bot removal, session revocation, Redis loss, database timeout, and duplicate writes.
@@ -0,0 +1,79 @@
1
+ # Threat model
2
+
3
+ ## Protected assets
4
+
5
+ - Discord bot token and OAuth client secret.
6
+ - OAuth access and refresh tokens.
7
+ - Session tokens and active sessions.
8
+ - Guild settings and moderation actions.
9
+ - Audit history and owner policies.
10
+ - Realtime events that may reveal guild state.
11
+ - Availability of the dashboard and Discord API allowance.
12
+
13
+ ## Attackers considered
14
+
15
+ - An unauthenticated internet client.
16
+ - An authenticated Discord user without permission for the target guild.
17
+ - A former guild manager whose role was removed while a session remains open.
18
+ - A malicious site attempting cross-site requests or WebSocket connections.
19
+ - A user replaying a request, OAuth callback, or idempotency key.
20
+ - A user sending many requests, large socket messages, or slow-client backpressure.
21
+ - An application bug that logs or returns secrets.
22
+ - A compromised low-privilege database account.
23
+ - A package supply-chain attacker.
24
+
25
+ ## Main controls
26
+
27
+ | Threat | Control |
28
+ |---|---|
29
+ | Session theft from script | HttpOnly cookie; no localStorage requirement |
30
+ | Session database leak | Only token hashes are stored |
31
+ | Session fixation | New opaque token on login and scheduled rotation |
32
+ | CSRF | Exact origin check plus session-bound token on unsafe methods |
33
+ | OAuth login CSRF or callback replay | One-time state plus browser nonce binding |
34
+ | Open redirect | Local return paths only |
35
+ | Guild ID substitution | Resource and permission checks run on parsed server input |
36
+ | Stale manager permission | Live authorization option for writes |
37
+ | Bot overreach | Required bot permissions are checked separately |
38
+ | Double submission | Idempotency reservation and response replay |
39
+ | Concurrent setting overwrite | Resource lock; application revision check recommended |
40
+ | Request flooding | Per-action store-backed limits |
41
+ | Slow upstream | Deadline, abort signal, retry policy, and circuit breaker utility |
42
+ | WebSocket cross-site use | Origin allowlist and session resolution |
43
+ | Unauthorized channel subscription | Authorization callback per channel |
44
+ | Socket memory pressure | Payload, subscription, lifetime, idle, and buffered-byte caps |
45
+ | Secret exposure in audit | Known-key redaction and caller responsibility |
46
+ | Event before commit | Durable outbox option |
47
+ | Owner policy loss after restart | Durable PolicyStore implementation |
48
+ | Malicious package release | Protected repository, CI tests, npm trusted publishing, provenance |
49
+
50
+ ## Out of scope
51
+
52
+ GuildGate does not:
53
+
54
+ - Secure a compromised host or stolen deployment secret.
55
+ - Configure TLS, a reverse proxy, a firewall, database roles, backups, or operating-system updates.
56
+ - Validate application-specific setting schemas unless the action supplies a parser.
57
+ - Create database transactions for an unknown driver.
58
+ - Decide which Discord command or moderation operation is appropriate.
59
+ - Prevent a bot owner from intentionally granting excessive access in application policy.
60
+ - Replace dependency review or incident response.
61
+
62
+ ## Open risks in 0.1.0
63
+
64
+ - Redis leases have no renewal helper. Keep the lock TTL above the expected operation time or use a driver with stronger locking.
65
+ - The included Discord REST helper has a small retry policy but does not coordinate a process-wide Discord route bucket. Reuse a Discord library REST manager when the application already has one.
66
+ - General audit writes happen after the action result. Put mandatory domain audit records inside the database transaction.
67
+ - Live Discord authorization adds API requests and can be affected by Discord availability. A bot gateway cache with event-based invalidation may be preferable at scale.
68
+ - The memory store uses one process and loses records on restart.
69
+
70
+ ## Review triggers
71
+
72
+ Review this model when:
73
+
74
+ - A new store or framework adapter is added.
75
+ - Owner APIs are exposed.
76
+ - Realtime client-to-server commands are added.
77
+ - Premium, billing, or account linking is added.
78
+ - A Discord permission flag or OAuth behavior changes.
79
+ - A release changes session, token, idempotency, lock, audit, or outbox behavior.
@@ -0,0 +1,41 @@
1
+ # Araştırma notları
2
+
3
+ İnceleme tarihi: 25 Temmuz 2026.
4
+
5
+ ## Yazım kontrolü
6
+
7
+ Wikipedia “Signs of AI writing” sayfası kesin yazar tespiti sunmaz. İçerik, kelime ve dilbilgisi, biçim, kullanıcıya konuşan hazır metin, işaretleme kalıntıları, kaynak hataları, edit özeti ve eski model davranışları altında olası işaretleri toplar.
8
+
9
+ GuildGate bu başlıkları `docs/tr/yazim-kilavuzu.md` dosyasında proje kurallarına çevirdi. `guildgate-writing-check` komutu da hazır asistan cümlelerini, model içi kaynak kalıntılarını, takip parametrelerini, boş şablonları ve belirsiz tanıtım kelimelerini sürüm kontrolünde arar.
10
+
11
+ Kaynak: https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing
12
+
13
+ ## Discord OAuth ve sunucu yetkisi
14
+
15
+ Discord authorization-code girişinde `state` kullanımı istek bütünlüğü için önerilir. GuildGate state kaydını hash’ler, ayrı tarayıcı nonce çereziyle eşler ve callback sırasında tek kez tüketir.
16
+
17
+ Varsayılan scope değerleri `identify` ve `guilds` olarak belirlenmiştir. Discord izin değeri güvenli JavaScript sayı sınırını aşabildiği için string olarak gelir; GuildGate bunu `BigInt` ile işler. Kullanıcı izni ve bot izni ayrı kontrol edilir.
18
+
19
+ Kaynaklar:
20
+
21
+ - https://docs.discord.com/developers/topics/oauth2
22
+ - https://docs.discord.com/developers/resources/user#get-current-user-guilds
23
+ - https://docs.discord.com/developers/topics/permissions
24
+
25
+ ## Oturum, CSRF ve WebSocket
26
+
27
+ OWASP oturum kimliğinin anlamsız olmasını ve asıl verinin sunucuda tutulmasını önerir. GuildGate ham oturum tokenını yalnızca istemciye verir ve sürücüye SHA-256 hash yazar.
28
+
29
+ Çerezle kimlik doğrulanan yazma isteklerinde tam origin ve oturuma bağlı CSRF tokenı gerekir. WebSocket bağlantısında origin ve oturum ilk bağlantıda doğrulanır; oturum belirli aralıklarla yeniden kontrol edilir ve her kanal aboneliği ayrıca yetkilendirilir.
30
+
31
+ Kaynaklar:
32
+
33
+ - https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html
34
+ - https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html
35
+ - https://cheatsheetseries.owasp.org/cheatsheets/WebSocket_Security_Cheat_Sheet.html
36
+
37
+ ## npm yayını
38
+
39
+ npm trusted publishing, desteklenen CI sağlayıcısından OIDC kullanır ve uzun süreli yayın tokenı ihtiyacını kaldırır. Paketteki GitHub release workflow’u testlerden sonra `id-token: write` izniyle npm yayını yapacak şekilde hazırlanmıştır. npm tarafında depo ve workflow güven ilişkisi önceden tanımlanmalıdır.
40
+
41
+ Kaynak: https://docs.npmjs.com/trusted-publishers
@@ -0,0 +1,7 @@
1
+ # Güvenlik bildirimi
2
+
3
+ Şüpheli güvenlik açığı için herkese açık issue açmayın. Depo kullanıma açıldığında GitHub private vulnerability reporting özelliğini kullanın.
4
+
5
+ Bildirimde etkilenen sürüm, gerekli ayarlar, tekrar adımları, beklenen ve görülen davranış, olası etki ve denenmiş geçici çözüm bulunmalıdır. Gerçek bot tokenı, OAuth sırrı, oturum çerezi, veritabanı bilgisi veya kullanıcı verisi eklemeyin.
6
+
7
+ `1.0.0` öncesinde yalnızca en yeni minor sürüm güvenlik düzeltmesi alır. Güvenlik sürümünde etkilenen sürüm aralığı, etki, gerekli koşullar ve güncelleme adımları açıkça yazılır.
@@ -0,0 +1,63 @@
1
+ # Kurulum ve ilk yayın
2
+
3
+ ## 1. Depoyu hazırlama
4
+
5
+ ```bash
6
+ unzip guildgate-0.1.0.zip
7
+ cd guildgate-0.1.0
8
+ npm install
9
+ npm test
10
+ ```
11
+
12
+ İlk internet bağlantılı geliştirme bilgisayarında `npm install`, `package-lock.json` dosyasını oluşturur. İlk pull request öncesinde bu dosyayı commit edin.
13
+
14
+ ## 2. Yapılandırma kontrolü
15
+
16
+ `.env.example` dosyasını özel bir ortam dosyasına kopyalayın ve her gizli değer için ayrı rastgele veri üretin.
17
+
18
+ ```bash
19
+ node ./bin/guildgate-doctor.mjs
20
+ ```
21
+
22
+ Son kontrolde `GUILDGATE_ENVIRONMENT=production` kullanın. Doctor; HTTPS, origin listesi, gizli değer uzunlukları ve token şifreleme anahtarını kontrol eder.
23
+
24
+ ## 3. GitHub deposu
25
+
26
+ `kavtuai` hesabında `guildgate` adında boş ve herkese açık bir depo oluşturun.
27
+
28
+ ```bash
29
+ git init
30
+ git branch -M main
31
+ git add .
32
+ git commit -m "feat: initial GuildGate release"
33
+ git remote add origin git@github.com:kavtuai/guildgate.git
34
+ git push -u origin main
35
+ ```
36
+
37
+ `main` dalı için koruma, zorunlu CI ve CodeQL kontrolü, pull request incelemesi, secret scanning, private vulnerability reporting ve Dependabot özelliklerini açın.
38
+
39
+ ## 4. npm ayarı
40
+
41
+ Paket adı `@kavtuai/guildgate` olarak tanımlıdır. npm tarafında `kavtuai` scope’u herkese açık scoped paket yayımlayabilmelidir.
42
+
43
+ npm trusted publishing ayarını bu GitHub deposu ve `.github/workflows/publish.yml` dosyasıyla eşleyin. Bu yapı GitHub OIDC kullanır ve uzun süreli npm tokenı gerektirmez.
44
+
45
+ Yayın öncesi:
46
+
47
+ ```bash
48
+ npm login
49
+ npm whoami
50
+ npm run pack:check
51
+ ```
52
+
53
+ ## 5. İlk uygulama bağlantısı
54
+
55
+ 1. Kalıcı ve kısa ömürlü veri sürücülerini seçin.
56
+ 2. Çekirdeği kurun ve doctor komutunu çalıştırın.
57
+ 3. Discord OAuth başlangıç ve callback endpoint’lerini ekleyin.
58
+ 4. Giriş yapmış frontend’e CSRF tokenı veren başlangıç endpoint’ini ekleyin.
59
+ 5. Bir okuma ve bir idempotent yazma işlemi hazırlayın.
60
+ 6. Yazma işlemine canlı Discord sunucu yetkisi kontrolü ekleyin.
61
+ 7. Denetim ve outbox saklama görevlerini hazırlayın.
62
+ 8. HTTP yetkilendirmesi tamamlandıktan sonra gerçek zamanlı merkezi bağlayın.
63
+ 9. Rol kaldırma, botu sunucudan çıkarma, oturum iptali, Redis kesintisi, veritabanı zaman aşımı ve çift kayıt senaryolarını test edin.
@@ -0,0 +1,59 @@
1
+ # Mimari
2
+
3
+ GuildGate politika, taşıyıcı, Discord erişimi ve veri saklamayı birbirinden ayırır. Çekirdek paket Fastify, Express, Redis, PostgreSQL, MongoDB veya WebSocket sunucusu import etmez.
4
+
5
+ ## Bileşenler
6
+
7
+ 1. **Çekirdek**, oturum, origin, CSRF, engel, bakım, limit, yetki, idempotency, kilit, zaman aşımı, denetim, cache ve gerçek zamanlı teslim kontrollerini yürütür.
8
+ 2. **Oturum yöneticisi**, ham token yerine SHA-256 hash kaydeder. Süre, boşta kalma, yenileme, oturum sayısı ve iptal kurallarını uygular.
9
+ 3. **Discord OAuth istemcisi**, tek kullanımlık state üretir, state’i tarayıcı nonce değeriyle eşler, code değişimini yapar, şifreli kimlik bilgilerini yeniler ve iptal eder.
10
+ 4. **Discord yetkilendiricisi**, kullanıcının OAuth sunucu izinlerini botun güncel rol ve izinleriyle ayrı ayrı kontrol eder.
11
+ 5. **Veri arayüzleri**, her uygulamanın kendi veritabanını seçmesini sağlar.
12
+ 6. **Framework bağlayıcıları**, framework tiplerini çekirdeğe taşımadan istek ve cevap nesnelerini çevirir.
13
+ 7. **Gerçek zamanlı merkez**, bağlantıyı doğrular, her aboneliği yetkilendirir, mesajları sınırlar ve oturum iptalinde socket’i kapatır.
14
+ 8. **Outbox dağıtıcısı**, kalıcı outbox sürücüsündeki commit edilmiş olayları yayımlar.
15
+
16
+ Bileşen şeması: [`../uml/components.mmd`](../uml/components.mmd).
17
+
18
+ ## İşlem sırası
19
+
20
+ Kimlik doğrulamalı bir yazma isteğinde varsayılan sıra:
21
+
22
+ 1. Oturumu çöz ve zamanı geldiyse kimliği yenile.
23
+ 2. İstek origin değerini tam eşleşmeyle kontrol et.
24
+ 3. CSRF tokenını oturum hash’iyle doğrula.
25
+ 4. Girdiyi doğrula.
26
+ 5. Korunan kaynağı belirle.
27
+ 6. Bakım ve engel politikalarını uygula.
28
+ 7. İşlem limitini uygula.
29
+ 8. Uygulama veya Discord yetkilendirmesini çalıştır.
30
+ 9. Idempotency anahtarını ayır.
31
+ 10. Kaynak kilidini al.
32
+ 11. İşlemi tek zaman sınırı altında çalıştır.
33
+ 12. Transaction dışındaki takip işlerinden önce idempotency kaydını tamamla.
34
+ 13. Cache etiketlerini temizle.
35
+ 14. Olayları outbox’a yaz veya doğrudan yayımla.
36
+ 15. Denetim olayını yaz.
37
+ 16. Kilidi bırak.
38
+
39
+ Sıra şeması: [`../uml/action-sequence.mmd`](../uml/action-sequence.mmd).
40
+
41
+ ## Transaction sınırı
42
+
43
+ GuildGate, tanımadığı bir veritabanı sürücüsü için transaction oluşturamaz. Transaction, action içindeki `execute()` fonksiyonuna aittir.
44
+
45
+ Zorunlu denetim kaydı ayar değişikliğiyle aynı transaction içinde olmalıysa uygulama bu kaydı `execute()` içinde yazmalıdır. Çekirdeğin genel denetim kaydı işlem sonucundan sonra yazılır ve commit edilmiş bir transaction’ı geri alamaz.
46
+
47
+ ## Tutarlılık seçimi
48
+
49
+ - Oturum ve OAuth state kayıtları tek kullanımlı ve fail-closed olmalıdır.
50
+ - Birden fazla instance için idempotency ve kilit işlemleri atomik olmalıdır.
51
+ - Görüntüleme verileri kısa süre cache’lenebilir.
52
+ - İzin gerektiren yazma işlemleri canlı Discord kontrolü veya olaylarla temizlenen bot cache’i kullanmalıdır.
53
+ - Denetim ve outbox için kalıcı veri saklama önerilir.
54
+ - Yeniden başlatma sonrasında olay teslimi gerekiyorsa outbox kullanılmalıdır.
55
+
56
+
57
+ ## Commit sonrası sorunlar
58
+
59
+ `execute()` döndüğünde uygulama kaydı commit etmiş olabilir. Bu nedenle cache, realtime veya genel denetim hatası domain işlemini yeniden çalıştırmaz. Sonuç başarılı döner ve sorunlar `meta.postCommitIssues` içinde bildirilir. Audit için fail-closed kullanılan işlemlerde idempotency zorunludur. Zorunlu ve atomik domain denetimi yine `execute()` içindeki veritabanı transaction’ına yazılmalıdır.
@@ -0,0 +1,7 @@
1
+ # Sahip yönetimi
2
+
3
+ Çekirdeğin `owner` metotları uygulama içi API’dir. HTTP isteğini kendi başına kontrol etmez. Bu metotları yalnızca sahip oturumu isteyen `action()` tanımları içinden çağırın.
4
+
5
+ Sahip işlemlerinde de origin, CSRF, rate limit, idempotency ve denetim kaydı kullanılmalıdır. Bakım modu, kullanıcı veya sunucu engeli ve oturum iptali için işlem nedeni denetim kaydına eklenmelidir.
6
+
7
+ Salt okunur sahip ekranı `gate.sessions.list(userId)` ve sürücü destekliyorsa `gate.config.stores.audit.list()` kullanabilir. Oturum hash’i, OAuth ciphertext, ham IP veya exception stack bilgisi tarayıcıya döndürülmemelidir.
@@ -0,0 +1,39 @@
1
+ # Tehdit modeli
2
+
3
+ ## Korunan veriler
4
+
5
+ Discord bot tokenı, OAuth sırrı, OAuth tokenları, oturumlar, sunucu ayarları, moderasyon işlemleri, denetim geçmişi, sahip politikaları ve gerçek zamanlı sunucu olayları korunur.
6
+
7
+ ## Dikkate alınan saldırılar
8
+
9
+ - Kimlik doğrulamamış internet isteği.
10
+ - Hedef sunucuda yetkisi olmayan oturum sahibi.
11
+ - Rolü kaldırılmış ancak paneli açık kalan eski yönetici.
12
+ - CSRF veya siteler arası WebSocket bağlantısı kuran başka site.
13
+ - OAuth callback, istek veya idempotency tekrar saldırısı.
14
+ - Çok sayıda istek, büyük socket mesajı veya yavaş istemci.
15
+ - Gizli değerleri loglayan uygulama hatası.
16
+ - Düşük yetkili veritabanı hesabının ele geçirilmesi.
17
+ - Paket yayın zincirine müdahale.
18
+
19
+ ## Başlıca kontroller
20
+
21
+ - HttpOnly oturum çerezi ve sunucuda yalnızca token hash’i.
22
+ - Girişte ve belirli aralıklarla yeni oturum kimliği.
23
+ - Yazma isteklerinde tam origin ve oturuma bağlı CSRF kontrolü.
24
+ - OAuth state için tek kullanımlık kayıt ve tarayıcı nonce eşlemesi.
25
+ - Harici adrese yönlendirmeyi reddeden yerel dönüş path’i.
26
+ - Kullanıcı ve bot Discord izinlerinin ayrı kontrolü.
27
+ - İzin gerektiren yazmalarda canlı kontrol seçeneği.
28
+ - Idempotency kaydı, kaynak kilidi ve uygulama revision kontrolü.
29
+ - İşlem bazlı rate limit ve zaman aşımı.
30
+ - Kanal başına WebSocket abonelik yetkisi.
31
+ - Mesaj boyutu, abonelik, boşta kalma, ömür ve buffer sınırı.
32
+ - Gizli alanları maskeleyen denetim kaydı.
33
+ - Commit sonrasında teslim için outbox.
34
+
35
+ ## Kapsam dışı
36
+
37
+ GuildGate ele geçirilmiş sunucuyu, çalınmış deployment sırrını, TLS ve firewall kurulumunu, veritabanı rollerini, yedeklemeyi, uygulamaya özel şema doğrulamasını veya yanlış yazılmış bot politikasını kendiliğinden düzeltemez.
38
+
39
+ 0.1.0 sürümünde Redis kilit yenileme yardımcısı yoktur. Genel denetim kaydı action sonucundan sonra yazılır. Discord REST yardımcısı süreç genelinde route bucket yöneticisi değildir. Bu sınırlar üretim tasarımında hesaba katılmalıdır.
@@ -0,0 +1,23 @@
1
+ # Özel veritabanı sürücüleri
2
+
3
+ GuildGate bir veritabanı seçmez. `GuildGateStores` içindeki arayüzleri uygulayıp `createGuildGate()` fonksiyonuna verin.
4
+
5
+ ## Kayıtların yerleştirilmesi
6
+
7
+ - Oturum, OAuth state, rate limit, cache, idempotency ve kısa süreli kilitler Redis benzeri atomik bir serviste tutulabilir.
8
+ - Şifreli OAuth kimlik bilgileri, denetim, outbox ve politikalar kalıcı veritabanında tutulmalıdır.
9
+ - Outbox’ın domain kaydıyla aynı veritabanında olması commit ile olay teslimi arasındaki boşluğu azaltır.
10
+
11
+ ## Zorunlu davranışlar
12
+
13
+ - `OAuthStateStore.consume()` okuma ve silmeyi tek atomik işlemde yapmalıdır.
14
+ - `RateLimitStore.hit()` eşzamanlı isteklerde limiti aşan maliyeti kabul etmemelidir.
15
+ - `IdempotencyStore.begin()` aynı anahtar için tek ilk yazara izin vermelidir.
16
+ - `LockStore.release()` kilidi silmeden önce tokenı karşılaştırmalıdır.
17
+ - `AuditStore` için mümkünse sadece ekleme yetkisi olan ayrı veritabanı rolü kullanılmalıdır.
18
+ - Birden fazla outbox worker varsa kayıt sahipliği veya `skip locked` benzeri bir yöntem kullanılmalıdır.
19
+ - `PolicyStore.bumpPolicyVersion()` atomik olmalıdır.
20
+
21
+ Ham oturum tokenı veri sürücüsüne verilmez. Çekirdek yalnızca `idHash` kaydeder. OAuth tokenları da `TokenCipher` çıktısı olarak saklanır.
22
+
23
+ Her sürücü; eşzamanlı state tüketimi, idempotency yarışı, limit yarışı, yanlış tokenla kilit bırakma, cache etiketi temizleme ve iki worker’ın aynı outbox kaydını alma senaryolarıyla test edilmelidir.