-
Notifications
You must be signed in to change notification settings - Fork 388
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into refac/users
- Loading branch information
Showing
84 changed files
with
5,207 additions
and
520 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# This workflow must be kept in sync to some extent with bot.yml | ||
name: GitHub Bot Proxy | ||
|
||
on: | ||
# Watch for any completed run on bot.yml workflow | ||
workflow_run: | ||
workflows: [GitHub Bot] | ||
types: [completed] | ||
|
||
jobs: | ||
# This workflow monitors any run completed on the GitHub Bot workflow and | ||
# checks if the event that triggered it is limited to read-only permissions | ||
# (e.g 'pull_request_review' on a pull request opened from a fork). | ||
# In this case, it reruns the GitHub Bot workflow using a 'workflow_dispatch' | ||
# event, thereby allowing it to run with write permissions. | ||
# | ||
# Complete flow: | ||
# 'pull_request_review' from fork on bot.yml (read-only) -> 'workflow_run' on bot-proxy.yml (write) -> 'workflow_dispatch' on bot.yml (write) | ||
rerun-with-write-perm: | ||
name: Rerun Bot with write permission | ||
# Skip this workflow if the original event is not 'pull_request_review' | ||
if: github.event.workflow_run.event == 'pull_request_review' | ||
runs-on: ubuntu-latest | ||
permissions: | ||
actions: write | ||
|
||
steps: | ||
- name: Download artifact from previous run | ||
uses: actions/download-artifact@v4 | ||
with: | ||
name: pr-number | ||
run-id: ${{ github.event.workflow_run.id }} | ||
github-token: ${{ secrets.GITHUB_TOKEN }} | ||
# Even if the artifact doesn't exist, do not mark the workflow as failed | ||
# Useful if the 'pull_request_review' event was emitted by a PR opened | ||
# from a branch on the main repo, so it has already been processed by | ||
# the bot workflow, and no artifact has been uploaded. | ||
continue-on-error: true | ||
id: download | ||
|
||
- name: Send workflow_dispatch event to Github Bot | ||
# Run only if an artifact was downloaded | ||
if: steps.download.outcome == 'success' | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
REPO: ${{ github.event.workflow_run.repository.full_name }} | ||
run: | | ||
gh workflow run bot.yml -R "$REPO" -f "pull-request-list=$(cat pr-number)" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
module gno.land/p/demo/avl/rotree |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
// Package rotree provides a read-only wrapper for avl.Tree with safe value transformation. | ||
// | ||
// It is useful when you want to expose a read-only view of a tree while ensuring that | ||
// the sensitive data cannot be modified. | ||
// | ||
// Example: | ||
// | ||
// // Define a user structure with sensitive data | ||
// type User struct { | ||
// Name string | ||
// Balance int | ||
// Internal string // sensitive field | ||
// } | ||
// | ||
// // Create and populate the original tree | ||
// privateTree := avl.NewTree() | ||
// privateTree.Set("alice", &User{ | ||
// Name: "Alice", | ||
// Balance: 100, | ||
// Internal: "sensitive", | ||
// }) | ||
// | ||
// // Create a safe transformation function that copies the struct | ||
// // while excluding sensitive data | ||
// makeEntrySafeFn := func(v interface{}) interface{} { | ||
// u := v.(*User) | ||
// return &User{ | ||
// Name: u.Name, | ||
// Balance: u.Balance, | ||
// Internal: "", // omit sensitive data | ||
// } | ||
// } | ||
// | ||
// // Create a read-only view of the tree | ||
// PublicTree := rotree.Wrap(tree, makeEntrySafeFn) | ||
// | ||
// // Safely access the data | ||
// value, _ := roTree.Get("alice") | ||
// user := value.(*User) | ||
// // user.Name == "Alice" | ||
// // user.Balance == 100 | ||
// // user.Internal == "" (sensitive data is filtered) | ||
package rotree | ||
|
||
import ( | ||
"gno.land/p/demo/avl" | ||
) | ||
|
||
// Wrap creates a new ReadOnlyTree from an existing avl.Tree and a safety transformation function. | ||
// If makeEntrySafeFn is nil, values will be returned as-is without transformation. | ||
// | ||
// makeEntrySafeFn is a function that transforms a tree entry into a safe version that can be exposed to external users. | ||
// This function should be implemented based on the specific safety requirements of your use case: | ||
// | ||
// 1. No-op transformation: For primitive types (int, string, etc.) or already safe objects, | ||
// simply pass nil as the makeEntrySafeFn to return values as-is. | ||
// | ||
// 2. Defensive copying: For mutable types like slices or maps, you should create a deep copy | ||
// to prevent modification of the original data. | ||
// Example: func(v interface{}) interface{} { return append([]int{}, v.([]int)...) } | ||
// | ||
// 3. Read-only wrapper: Return a read-only version of the object that implements | ||
// a limited interface. | ||
// Example: func(v interface{}) interface{} { return NewReadOnlyObject(v) } | ||
// | ||
// 4. DAO transformation: Transform the object into a data access object that | ||
// controls how the underlying data can be accessed. | ||
// Example: func(v interface{}) interface{} { return NewDAO(v) } | ||
// | ||
// The function ensures that the returned object is safe to expose to untrusted code, | ||
// preventing unauthorized modifications to the original data structure. | ||
func Wrap(tree *avl.Tree, makeEntrySafeFn func(interface{}) interface{}) *ReadOnlyTree { | ||
return &ReadOnlyTree{ | ||
tree: tree, | ||
makeEntrySafeFn: makeEntrySafeFn, | ||
} | ||
} | ||
|
||
// ReadOnlyTree wraps an avl.Tree and provides read-only access. | ||
type ReadOnlyTree struct { | ||
tree *avl.Tree | ||
makeEntrySafeFn func(interface{}) interface{} | ||
} | ||
|
||
// Verify that ReadOnlyTree implements ITree | ||
var _ avl.ITree = (*ReadOnlyTree)(nil) | ||
|
||
// getSafeValue applies the makeEntrySafeFn if it exists, otherwise returns the original value | ||
func (roTree *ReadOnlyTree) getSafeValue(value interface{}) interface{} { | ||
if roTree.makeEntrySafeFn == nil { | ||
return value | ||
} | ||
return roTree.makeEntrySafeFn(value) | ||
} | ||
|
||
// Size returns the number of key-value pairs in the tree. | ||
func (roTree *ReadOnlyTree) Size() int { | ||
return roTree.tree.Size() | ||
} | ||
|
||
// Has checks whether a key exists in the tree. | ||
func (roTree *ReadOnlyTree) Has(key string) bool { | ||
return roTree.tree.Has(key) | ||
} | ||
|
||
// Get retrieves the value associated with the given key, converted to a safe format. | ||
func (roTree *ReadOnlyTree) Get(key string) (interface{}, bool) { | ||
value, exists := roTree.tree.Get(key) | ||
if !exists { | ||
return nil, false | ||
} | ||
return roTree.getSafeValue(value), true | ||
} | ||
|
||
// GetByIndex retrieves the key-value pair at the specified index in the tree, with the value converted to a safe format. | ||
func (roTree *ReadOnlyTree) GetByIndex(index int) (string, interface{}) { | ||
key, value := roTree.tree.GetByIndex(index) | ||
return key, roTree.getSafeValue(value) | ||
} | ||
|
||
// Iterate performs an in-order traversal of the tree within the specified key range. | ||
func (roTree *ReadOnlyTree) Iterate(start, end string, cb avl.IterCbFn) bool { | ||
return roTree.tree.Iterate(start, end, func(key string, value interface{}) bool { | ||
return cb(key, roTree.getSafeValue(value)) | ||
}) | ||
} | ||
|
||
// ReverseIterate performs a reverse in-order traversal of the tree within the specified key range. | ||
func (roTree *ReadOnlyTree) ReverseIterate(start, end string, cb avl.IterCbFn) bool { | ||
return roTree.tree.ReverseIterate(start, end, func(key string, value interface{}) bool { | ||
return cb(key, roTree.getSafeValue(value)) | ||
}) | ||
} | ||
|
||
// IterateByOffset performs an in-order traversal of the tree starting from the specified offset. | ||
func (roTree *ReadOnlyTree) IterateByOffset(offset int, count int, cb avl.IterCbFn) bool { | ||
return roTree.tree.IterateByOffset(offset, count, func(key string, value interface{}) bool { | ||
return cb(key, roTree.getSafeValue(value)) | ||
}) | ||
} | ||
|
||
// ReverseIterateByOffset performs a reverse in-order traversal of the tree starting from the specified offset. | ||
func (roTree *ReadOnlyTree) ReverseIterateByOffset(offset int, count int, cb avl.IterCbFn) bool { | ||
return roTree.tree.ReverseIterateByOffset(offset, count, func(key string, value interface{}) bool { | ||
return cb(key, roTree.getSafeValue(value)) | ||
}) | ||
} | ||
|
||
// Set is not supported on ReadOnlyTree and will panic. | ||
func (roTree *ReadOnlyTree) Set(key string, value interface{}) bool { | ||
panic("Set operation not supported on ReadOnlyTree") | ||
} | ||
|
||
// Remove is not supported on ReadOnlyTree and will panic. | ||
func (roTree *ReadOnlyTree) Remove(key string) (value interface{}, removed bool) { | ||
panic("Remove operation not supported on ReadOnlyTree") | ||
} | ||
|
||
// RemoveByIndex is not supported on ReadOnlyTree and will panic. | ||
func (roTree *ReadOnlyTree) RemoveByIndex(index int) (key string, value interface{}) { | ||
panic("RemoveByIndex operation not supported on ReadOnlyTree") | ||
} |
Oops, something went wrong.