Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
entのPrivacy機能とgo/astを使って、意図しないDBアクセスを防ぐ
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
KazukiHayase
December 05, 2025
410
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
entのPrivacy機能とgo/astを使って、意図しないDBアクセスを防ぐ
KazukiHayase
December 05, 2025
More Decks by KazukiHayase
See All by KazukiHayase
go testのキャッシュの仕組みにDeep Diveする
kazukihayase
0
170
要件定義・デザインフェーズでもAIを活用して、コミュニケーションの密度を高める
kazukihayase
0
580
CIでのgolangci-lintの実行を約90%削減した話
kazukihayase
0
560
もし今からGraphQLを採用するなら
kazukihayase
13
6k
Goでテストをしやすくするためにやったこと
kazukihayase
1
930
GraphQLクライアントの技術選定 2023冬
kazukihayase
9
7.9k
Introduction and Insights of the Hasura-based Architecture
kazukihayase
0
1.2k
自分だけが頑張るのをやめて、フルスタックなチームを作る
kazukihayase
2
3.7k
Goでテンプレートからファイルを自動生成するCLIを作る
kazukihayase
0
1.6k
Featured
See All Featured
KATA
mclloyd
PRO
35
15k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.5k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
190
Measuring & Analyzing Core Web Vitals
bluesmoon
9
870
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
410
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
150
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
25k
Testing 201, or: Great Expectations
jmmastey
46
8.2k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
560
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
0
530
Designing Powerful Visuals for Engaging Learning
tmiket
1
410
Transcript
entのPrivacy機能とgo/astを使って、 意図しないDBアクセスを防ぐ 2025.12.05 layerx.go #3 ©2025 Dr.'s Prime ,Inc.
自己紹介 @KazukiHayase 早瀬和輝(Kazuki Hayase) 2025年4月ドクターズプライム入社 リードエンジニア Go / TypeScript /
React(Next.js) / GraphQL ダイエットのためにラーメン制限中 ©2025 Dr.'s Prime ,Inc.
会社概要 ©2025 Dr.'s Prime ,Inc.
会社概要 ©2025 Dr.'s Prime ,Inc.
01 背景 02 entのprivacy機能の活用 03 go/astを使った静的解析 04 まとめ ©2025 Dr.'s
Prime ,Inc.
1. 背景 ©2025 Dr.'s Prime ,Inc.
背景 やりたかったこと ユーザーのブロック機能を実装 特定のユーザーには、特定のアイテムを表示したくない アイテム一覧や検索結果から除外する必要がある ©2025 Dr.'s Prime ,Inc.
背景 データモデル 中間テーブルでブロック関係を保持 UserはブロックされているCompanyのItemは閲覧できない User BlockedUser Company Item blocked by
has blocks ©2025 Dr.'s Prime ,Inc.
背景 課題 将来的に機能が増えた際、フィルタリング処理が漏れる可能性 新しい一覧画面を追加 新しいメール配信機能を追加 etc... → フィルタリング漏れを防ぐ仕組みが必要 ©2025 Dr.'s
Prime ,Inc.
背景 一般的なアプローチ Repository層やUseCase層でフィルタリング条件を追加 func (r *itemRepository) List(ctx context.Context, userID string)
([]*Item, error) { var items []*Item err := r.db. Joins("JOIN companies ON items.company_id = companies.id"). // 中間テーブルでブロックされていないItemを取得 Where("NOT EXISTS (SELECT 1 FROM blocked_users WHERE company_id = companies.id AND user_id = ?)", userID). Find(&items) if err != nil { return nil, err } return items, nil } → 実装者がフィルタリングを忘れる可能性がある ©2025 Dr.'s Prime ,Inc.
背景 解決方針 1. entのprivacy機能でSQLレベルでフィルタリングを強制 2. go/astで静的解析して実装漏れを検知 これらを組み合わせることで、フィルタリング漏れを防ぐ ©2025 Dr.'s Prime
,Inc.
2. entのprivacy機能の活用 ©2025 Dr.'s Prime ,Inc.
entのprivacy機能の活用 entのprivacy機能とは entが提供するフィルタリング機能 スキーマにポリシーを定義することで、全てのクエリに自動適用される https://entgo.io/ja/docs/privacy/ ©2025 Dr.'s Prime ,Inc.
entのprivacy機能の活用 privacy機能の利点 公式ドキュメントより引用 The main advantage of the privacy layer
is that, you write the privacy policy once (in the schema), and it is always evaluated. No matter where queries and mutations are performed in your codebase, it will always go through the privacy layer. → 一度定義すれば、どの経路でも必ずフィルタリングが適用される ©2025 Dr.'s Prime ,Inc.
entのprivacy機能の活用 スキーマでのポリシー定義 func (Item) Policy() ent.Policy { return privacy.Policy{ Mutation:
privacy.MutationPolicy{ // 全ての変更操作を許可(デフォルト) privacy.AlwaysAllowRule(), }, Query: privacy.QueryPolicy{ // カスタムフィルタリングルールを適用 rule.FilterBlockedUserRule(), }, } } ©2025 Dr.'s Prime ,Inc.
entのprivacy機能の活用 フィルタリングルールの実装 func FilterBlockedUserRule() privacy.QueryRule { return privacy.ItemQueryRuleFunc(func(ctx context.Context, q
*ent.ItemQuery) error { userID := ctxutil.UserID(ctx) if userID == "" { return privacy.Denyf("no user ID in context") } // ブロックされているユーザーのアイテムを除外するWhere句を付与 q.Where( item.Not( item.HasCompanyWith( company.HasBlockedUsersWith( blockeduser.UserIDEQ(userID), ), ), ), ) return privacy.Skip }) } ©2025 Dr.'s Prime ,Inc.
entのprivacy機能の活用 privacy機能のメリット テーブル単位でフィルタリングが強制される RepositoryやUseCaseでのフィルタリングが不要 取得経路が増えても、自動的にフィルタリングが適用される ©2025 Dr.'s Prime ,Inc.
entのprivacy機能の活用 privacy機能のデメリット SQLに付与されるWHERE句によるパフォーマンスの低下 より最適なWHERE句が付与できる可能性がある パフォーマンスと強制力のトレードオフの判断 ©2025 Dr.'s Prime ,Inc.
entのprivacy機能の活用 これで全て解決?🤔 ©2025 Dr.'s Prime ,Inc.
entのprivacy機能の活用 残る懸念点 privacy機能はcontextから情報を取得してフィルタリングを実行 contextの設定が漏れると、ランタイムエラーが発生 その状態でリリースされる可能性もゼロではない → 漏れている場合は実装時(テスト実行時)に検知したい ©2025 Dr.'s Prime
,Inc.
3. go/astを使った静的解析 ©2025 Dr.'s Prime ,Inc.
go/astを使った静的解析 Repository層での対応 contextを設定するプライベートメソッドを用意 func (repo *itemRepository) List(ctx context.Context, userID string)
([]*Item, error) { ctx = repo.setContext(ctx, userID) // contextを設定 // ...クエリを実行 } func (repo *itemRepository) setContext(ctx context.Context, userID string) context.Context { return ctxutil.SetUserID(ctx, userID) } ©2025 Dr.'s Prime ,Inc.
go/astを使った静的解析 go/astによる検証 go/astを使用して、Goのソースコードを抽象構文木(AST)を解析 ASTを走査して、メソッド呼び出しをチェック 全ての公開メソッドで setContext が呼ばれているかを確認 ©2025 Dr.'s Prime
,Inc.
go/astを使った静的解析 テストコードの例 func TestItemRepositoryMethodCallCheck(t *testing.T) { const ( targetStructName =
"itemRepository" targetSourceFileName = "item_repository.go" targetMethodName = "setContext" ) // AST解析で各メソッドがsetContextを呼んでいるかチェック gotCallMap, err := CheckMethodCallsInStruct(targetSourceFileName, targetStructName, targetMethodName) if err != nil { t.Fatal(err) } wantCallMap := map[string]bool{ "List": true, "GetByID": true, } if !reflect.DeepEqual(wantCallMap, gotCallMap) { t.Errorf("Method list mismatch.\nWanted: %v\nGot: %v", wantCallMap, gotCallMap) } } ©2025 Dr.'s Prime ,Inc.
go/astを使った静的解析 AST解析の実装(1/3) func CheckMethodCallsInStruct(targetFileName, targetStructName, targetMethodName string) (map[string]bool, error) {
// ソースファイルをパース fset := token.NewFileSet() node, err := parser.ParseFile(fset, targetFileName, nil, 0) if err != nil { return nil, err } // ASTを走査して、targetStructNameのメソッドを全て抽出し、 // targetMethodNameが呼び出されているかをcallMapに格納する callMap := make(map[string]bool) ast.Inspect(node, func(n ast.Node) bool { // 次のスライドに続く... }) return callMap, nil } ©2025 Dr.'s Prime ,Inc.
go/astを使った静的解析 AST解析の実装(2/3) ast.Inspect(node, func(n ast.Node) bool { // メソッド宣言のみ対象(レシーバーがない関数は除外) funcDecl,
ok := n.(*ast.FuncDecl) if !ok || funcDecl.Recv == nil { return true } // レシーバーの型名を取得 var recvTypeName string switch recv := funcDecl.Recv.List[0].Type.(type) { case *ast.StarExpr: if ident, ok := recv.X.(*ast.Ident); ok { recvTypeName = ident.Name } case *ast.Ident: recvTypeName = recv.Name } if recvTypeName != targetStructName { return true // 対象の構造体でない場合はスキップ } // 次のスライドに続く... }) ©2025 Dr.'s Prime ,Inc.
go/astを使った静的解析 AST解析の実装(3/3) ast.Inspect(node, func(n ast.Node) bool { // ...前のスライドから続く methodName
:= funcDecl.Name.Name // targetMethodNameの呼び出しをチェック isCalledTargetMethod := false ast.Inspect(funcDecl.Body, func(n ast.Node) bool { callExpr, ok := n.(*ast.CallExpr) if !ok { return true } selExpr, ok := callExpr.Fun.(*ast.SelectorExpr) if !ok { return true } if selExpr.Sel.Name == targetMethodName { isCalledTargetMethod = true return false } return true }) callMap[methodName] = isCalledTargetMethod return true }) ©2025 Dr.'s Prime ,Inc.
go/astを使った静的解析 メソッド追加時の例 setContext の呼び出しが漏れているメソッドを追加した場合 type itemRepository struct {} // ...他のメソッド
// 新規メソッド追加 func (repo *itemRepository) GetMulti(ctx context.Context, ids []string) ([]*Item, error) { return []*Item{}, nil } ©2025 Dr.'s Prime ,Inc.
go/astを使った静的解析 メソッド追加時の例 テストを実行すると GetMulti が wantCallMap に存在しないので失敗 ❯ go test
./... --- FAIL: TestItemRepositoryMethodCallCheck (0.00s) item_repository_test.go:30: Method list mismatch. Wanted: map[GetByID:true List:true] Got: map[GetByID:true GetMulti:false List:true] FAIL FAIL sample 0.251s FAIL ©2025 Dr.'s Prime ,Inc.
go/astを使った静的解析 go/astによる検証のメリット 実装が漏れている場合に、リリース前に検知可能 e.g. ローカルでのテスト実行時、CIで自動チェック 背景を知らない人でも、自然とルールに沿った実装になる ©2025 Dr.'s Prime ,Inc.
4. まとめ ©2025 Dr.'s Prime ,Inc.
まとめ 意図しないDBアクセスを仕組みで防ぐ entのPrivacy機能で取得時のフィルタリングを強制 go/astで静的解析し、ルールに沿って実装されているか検証 これにより、将来的な機能追加時も安心 ©2025 Dr.'s Prime ,Inc.
We Are Hiring! ぜひドクターズプライムの魅力を覗きにきてください! ©2025 Dr.'s Prime ,Inc.