pi-lens 3.8.21 → 3.8.22

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 (47) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +2 -0
  3. package/clients/dispatch/runners/lsp.ts +58 -3
  4. package/clients/dispatch/runners/tree-sitter.ts +467 -0
  5. package/clients/lsp/client.ts +229 -3
  6. package/clients/lsp/index.ts +111 -1
  7. package/clients/pipeline.ts +2 -2
  8. package/clients/runtime-session.ts +43 -5
  9. package/clients/tree-sitter-client.ts +162 -0
  10. package/clients/tree-sitter-logger.ts +47 -0
  11. package/clients/tree-sitter-query-loader.ts +13 -2
  12. package/package.json +3 -1
  13. package/rules/rule-catalog.json +64 -0
  14. package/rules/tree-sitter-queries/go/go-bare-error.yml +19 -7
  15. package/rules/tree-sitter-queries/go/go-command-injection.yml +55 -0
  16. package/rules/tree-sitter-queries/go/go-direct-panic.yml +45 -0
  17. package/rules/tree-sitter-queries/go/go-empty-if-err.yml +47 -0
  18. package/rules/tree-sitter-queries/go/go-goroutine-loop-capture.yml +49 -0
  19. package/rules/tree-sitter-queries/go/go-ignored-call-result.yml +51 -0
  20. package/rules/tree-sitter-queries/go/go-insecure-random.yml +51 -0
  21. package/rules/tree-sitter-queries/go/go-log-fatal.yml +49 -0
  22. package/rules/tree-sitter-queries/go/go-path-traversal.yml +51 -0
  23. package/rules/tree-sitter-queries/go/go-shared-map-write-goroutine.yml +54 -0
  24. package/rules/tree-sitter-queries/go/go-sql-injection.yml +55 -0
  25. package/rules/tree-sitter-queries/go/go-weak-hash.yml +51 -0
  26. package/rules/tree-sitter-queries/python/python-command-injection.yml +63 -0
  27. package/rules/tree-sitter-queries/python/python-insecure-deserialization.yml +48 -0
  28. package/rules/tree-sitter-queries/python/python-insecure-random.yml +51 -0
  29. package/rules/tree-sitter-queries/python/python-path-traversal.yml +55 -0
  30. package/rules/tree-sitter-queries/python/python-sql-injection.yml +47 -0
  31. package/rules/tree-sitter-queries/python/python-ssrf.yml +50 -0
  32. package/rules/tree-sitter-queries/python/python-thread-global-write.yml +58 -0
  33. package/rules/tree-sitter-queries/python/python-weak-hash.yml +51 -0
  34. package/rules/tree-sitter-queries/ruby/ruby-command-injection.yml +56 -0
  35. package/rules/tree-sitter-queries/ruby/ruby-insecure-deserialization.yml +47 -0
  36. package/rules/tree-sitter-queries/ruby/ruby-insecure-random.yml +54 -0
  37. package/rules/tree-sitter-queries/ruby/ruby-weak-hash.yml +50 -0
  38. package/rules/tree-sitter-queries/rust/rust-lock-held-across-await.yml +59 -0
  39. package/rules/tree-sitter-queries/typescript/ts-command-injection.yml +60 -0
  40. package/rules/tree-sitter-queries/typescript/ts-detached-async-call.yml +56 -0
  41. package/rules/tree-sitter-queries/typescript/ts-insecure-random.yml +54 -0
  42. package/rules/tree-sitter-queries/typescript/ts-ssrf.yml +53 -0
  43. package/rules/tree-sitter-queries/typescript/ts-weak-hash.yml +54 -0
  44. package/scripts/validate-rule-catalog.mjs +227 -0
  45. package/skills/lsp-navigation/SKILL.md +15 -3
  46. package/tools/lsp-navigation.js +259 -28
  47. package/tools/lsp-navigation.ts +294 -29
@@ -0,0 +1,51 @@
1
+ # Go Security
2
+ # Detects use of math/rand in potentially security-sensitive contexts.
3
+ id: go-insecure-random
4
+ name: Insecure Randomness
5
+ severity: warning
6
+ category: security
7
+ defect_class: injection
8
+ inline_tier: warning
9
+ language: go
10
+
11
+ message: "Insecure randomness source detected — use crypto/rand for security-sensitive values"
12
+
13
+ description: |
14
+ math/rand is deterministic and not suitable for security-sensitive randomness.
15
+
16
+ ✅ FIX: use crypto/rand for tokens, keys, nonces, and secrets.
17
+
18
+ query: |
19
+ (call_expression
20
+ function: (selector_expression
21
+ operand: (identifier) @PKG
22
+ field: (field_identifier) @FN)
23
+ arguments: (argument_list) @ARGS)
24
+ (#eq? @PKG "rand")
25
+ (#match? @FN "^(Int|Intn|Int63|Uint32|Uint64|Read|Float64)$")
26
+
27
+ metavars:
28
+ - PKG
29
+ - FN
30
+ - ARGS
31
+
32
+ cwe:
33
+ - CWE-330
34
+ owasp:
35
+ - A02
36
+ confidence: medium
37
+
38
+ has_fix: false
39
+
40
+ tags:
41
+ - go
42
+ - security
43
+ - randomness
44
+ - weak-prng
45
+
46
+ examples:
47
+ bad: |
48
+ code := rand.Intn(1000000)
49
+
50
+ good: |
51
+ _, _ = rand.Read(buf) // from crypto/rand
@@ -0,0 +1,49 @@
1
+ # Go Reliability
2
+ # Detects process-terminating log calls in non-boundary code.
3
+ id: go-log-fatal
4
+ name: log.Fatal / log.Panic Call
5
+ severity: warning
6
+ category: reliability
7
+ defect_class: safety
8
+ inline_tier: warning
9
+ language: go
10
+
11
+ message: "log.Fatal/log.Panic terminates execution — prefer returning errors from core logic"
12
+
13
+ description: |
14
+ `log.Fatal*` exits the process and `log.Panic*` panics. In shared/internal logic,
15
+ this makes control flow hard to test and recover.
16
+
17
+ ✅ FIX: return errors upward and let program entrypoints decide termination policy.
18
+
19
+ query: |
20
+ (call_expression
21
+ function: (selector_expression
22
+ operand: (identifier) @PKG
23
+ field: (field_identifier) @METHOD)
24
+ arguments: (argument_list) @ARGS)
25
+ (#eq? @PKG "log")
26
+ (#match? @METHOD "^(Fatal|Fatalf|Fatalln|Panic|Panicf|Panicln)$")
27
+
28
+ metavars:
29
+ - PKG
30
+ - METHOD
31
+ - ARGS
32
+
33
+ has_fix: false
34
+
35
+ tags:
36
+ - go
37
+ - reliability
38
+ - testability
39
+
40
+ examples:
41
+ bad: |
42
+ if err != nil {
43
+ log.Fatal(err)
44
+ }
45
+
46
+ good: |
47
+ if err != nil {
48
+ return err
49
+ }
@@ -0,0 +1,51 @@
1
+ # Go Security
2
+ # Detects file-system sink calls with dynamic path expressions.
3
+ id: go-path-traversal
4
+ name: Path Traversal Risk
5
+ severity: warning
6
+ category: security
7
+ defect_class: injection
8
+ inline_tier: warning
9
+ language: go
10
+
11
+ message: "Potential path traversal sink — sanitize and constrain file paths"
12
+
13
+ description: |
14
+ File operations with user-controlled paths can access unintended files.
15
+
16
+ ✅ FIX: clean/canonicalize paths and enforce a fixed base directory.
17
+
18
+ query: |
19
+ (call_expression
20
+ function: (selector_expression
21
+ operand: (identifier) @PKG
22
+ field: (field_identifier) @FN)
23
+ arguments: (argument_list
24
+ [(identifier) (binary_expression) (call_expression)] @PATH
25
+ (_)*))
26
+ (#match? @PKG "^(os|ioutil)$")
27
+ (#match? @FN "^(Open|OpenFile|ReadFile|WriteFile|Create|Remove|RemoveAll)$")
28
+
29
+ metavars:
30
+ - PKG
31
+ - FN
32
+ - PATH
33
+
34
+ post_filter: go_path_traversal_sink
35
+
36
+ has_fix: false
37
+
38
+ tags:
39
+ - go
40
+ - security
41
+ - path-traversal
42
+ - cwe-22
43
+ - owasp-a01
44
+
45
+ examples:
46
+ bad: |
47
+ os.ReadFile(base + userPath)
48
+
49
+ good: |
50
+ p := filepath.Clean(userPath)
51
+ os.ReadFile(filepath.Join(baseDir, p))
@@ -0,0 +1,54 @@
1
+ # Go Concurrency
2
+ # Detects map writes inside goroutines, often indicating unsafe shared mutation.
3
+ id: go-shared-map-write-goroutine
4
+ name: Shared Map Write in Goroutine
5
+ severity: warning
6
+ category: concurrency
7
+ defect_class: async-misuse
8
+ inline_tier: warning
9
+ language: go
10
+
11
+ message: "Map write inside goroutine may race — guard with synchronization or ownership boundaries"
12
+
13
+ description: |
14
+ Native Go maps are not safe for concurrent writes without synchronization.
15
+
16
+ ✅ FIX: use sync.Mutex/RWMutex, channels, or sync.Map based on access patterns.
17
+
18
+ query: |
19
+ (go_statement
20
+ expression: (call_expression
21
+ function: (func_literal
22
+ body: (block
23
+ (assignment_statement
24
+ left: (index_expression) @MAPWRITE
25
+ right: (_) @VALUE)))
26
+ arguments: (argument_list) @ARGS))
27
+
28
+ metavars:
29
+ - MAPWRITE
30
+ - VALUE
31
+ - ARGS
32
+
33
+ cwe:
34
+ - CWE-362
35
+ owasp:
36
+ - A09
37
+ confidence: medium
38
+
39
+ has_fix: false
40
+
41
+ tags:
42
+ - go
43
+ - concurrency
44
+ - map
45
+ - race
46
+
47
+ examples:
48
+ bad: |
49
+ go func() { m[key] = value }()
50
+
51
+ good: |
52
+ mu.Lock()
53
+ m[key] = value
54
+ mu.Unlock()
@@ -0,0 +1,55 @@
1
+ # Go Security
2
+ # Detects SQL query APIs fed by fmt.Sprintf/format-composed strings.
3
+ id: go-sql-injection
4
+ name: SQL Injection Risk
5
+ severity: warning
6
+ category: security
7
+ defect_class: injection
8
+ inline_tier: warning
9
+ language: go
10
+
11
+ message: "Potential SQL injection sink — use parameterized queries"
12
+
13
+ description: |
14
+ Building SQL with string formatting before Query/Exec can enable injection.
15
+
16
+ ✅ FIX: use placeholders and bind parameters in Query/Exec methods.
17
+
18
+ query: |
19
+ (call_expression
20
+ function: (selector_expression
21
+ field: (field_identifier) @DBFN)
22
+ arguments: (argument_list
23
+ (call_expression
24
+ function: (selector_expression
25
+ operand: (identifier) @FMTPKG
26
+ field: (field_identifier) @FMTFN)
27
+ arguments: (argument_list) @FMTARGS)
28
+ (_)*))
29
+ (#match? @DBFN "^(Query|QueryContext|QueryRow|QueryRowContext|Exec|ExecContext)$")
30
+ (#eq? @FMTPKG "fmt")
31
+ (#eq? @FMTFN "Sprintf")
32
+
33
+ metavars:
34
+ - DBFN
35
+ - FMTPKG
36
+ - FMTFN
37
+ - FMTARGS
38
+
39
+ post_filter: go_sql_injection_sink
40
+
41
+ has_fix: false
42
+
43
+ tags:
44
+ - go
45
+ - security
46
+ - sql-injection
47
+ - cwe-89
48
+ - owasp-a03
49
+
50
+ examples:
51
+ bad: |
52
+ db.Query(fmt.Sprintf("SELECT * FROM users WHERE id=%s", userID))
53
+
54
+ good: |
55
+ db.Query("SELECT * FROM users WHERE id=$1", userID)
@@ -0,0 +1,51 @@
1
+ # Go Security
2
+ # Detects weak cryptographic hash package usage.
3
+ id: go-weak-hash
4
+ name: Weak Hash Primitive
5
+ severity: warning
6
+ category: security
7
+ defect_class: injection
8
+ inline_tier: warning
9
+ language: go
10
+
11
+ message: "Weak hash primitive detected (md5/sha1) — use sha256+ for security-sensitive contexts"
12
+
13
+ description: |
14
+ md5/sha1 are not suitable for security-sensitive hashing.
15
+
16
+ ✅ FIX: use crypto/sha256 or stronger alternatives.
17
+
18
+ query: |
19
+ (call_expression
20
+ function: (selector_expression
21
+ operand: (identifier) @PKG
22
+ field: (field_identifier) @FN)
23
+ arguments: (argument_list) @ARGS)
24
+ (#match? @PKG "^(md5|sha1)$")
25
+ (#match? @FN "^(New|Sum)$")
26
+
27
+ metavars:
28
+ - PKG
29
+ - FN
30
+ - ARGS
31
+
32
+ cwe:
33
+ - CWE-327
34
+ owasp:
35
+ - A02
36
+ confidence: high
37
+
38
+ has_fix: false
39
+
40
+ tags:
41
+ - go
42
+ - security
43
+ - crypto
44
+ - weak-hash
45
+
46
+ examples:
47
+ bad: |
48
+ sum := md5.Sum(data)
49
+
50
+ good: |
51
+ sum := sha256.Sum256(data)
@@ -0,0 +1,63 @@
1
+ # Python Security
2
+ # Detects shell command execution sinks that commonly lead to command injection.
3
+ id: python-command-injection
4
+ name: Command Injection Sink
5
+ severity: warning
6
+ category: security
7
+ defect_class: injection
8
+ inline_tier: warning
9
+ language: python
10
+
11
+ message: "Potential command injection sink — avoid shell execution with dynamic input"
12
+
13
+ description: |
14
+ Calling shell execution APIs with user-controlled data can lead to command injection.
15
+
16
+ ✅ FIX: avoid shell execution; prefer argument arrays and strict input allowlists.
17
+
18
+ query: |
19
+ (call
20
+ function: (attribute
21
+ object: (identifier) @MOD
22
+ attribute: (identifier) @FN)
23
+ arguments: (argument_list) @ARGS)
24
+ (#eq? @MOD "os")
25
+ (#match? @FN "^(system|popen)$")
26
+
27
+ (call
28
+ function: (attribute
29
+ object: (identifier) @MOD
30
+ attribute: (identifier) @FN)
31
+ arguments: (argument_list
32
+ (keyword_argument
33
+ name: (identifier) @KW
34
+ value: (true))))
35
+ (#eq? @MOD "subprocess")
36
+ (#match? @FN "^(run|Popen|call|check_output|check_call)$")
37
+ (#eq? @KW "shell")
38
+
39
+ metavars:
40
+ - MOD
41
+ - FN
42
+ - ARGS
43
+ - KW
44
+
45
+ post_filter: py_command_injection_sink
46
+
47
+ has_fix: false
48
+
49
+ tags:
50
+ - python
51
+ - security
52
+ - command-injection
53
+ - cwe-78
54
+ - owasp-a03
55
+
56
+ examples:
57
+ bad: |
58
+ import os
59
+ os.system(user_input)
60
+
61
+ good: |
62
+ import subprocess
63
+ subprocess.run(["git", "status"], check=True)
@@ -0,0 +1,48 @@
1
+ # Python Security
2
+ # Detects unsafe deserialization APIs.
3
+ id: python-insecure-deserialization
4
+ name: Insecure Deserialization
5
+ severity: warning
6
+ category: security
7
+ defect_class: injection
8
+ inline_tier: warning
9
+ language: python
10
+
11
+ message: "Potential insecure deserialization sink — avoid unsafe loaders"
12
+
13
+ description: |
14
+ Deserializing untrusted input with pickle/yaml unsafe loaders can lead to code execution.
15
+
16
+ ✅ FIX: use safe parsing formats or safe loaders and strict schema validation.
17
+
18
+ query: |
19
+ (call
20
+ function: (attribute
21
+ object: (identifier) @MOD
22
+ attribute: (identifier) @FN)
23
+ arguments: (argument_list (_) @DATA))
24
+ (#match? @MOD "^(pickle|yaml)$")
25
+ (#match? @FN "^(load|loads|unsafe_load)$")
26
+
27
+ metavars:
28
+ - MOD
29
+ - FN
30
+ - DATA
31
+
32
+ post_filter: py_insecure_deserialization_sink
33
+
34
+ has_fix: false
35
+
36
+ tags:
37
+ - python
38
+ - security
39
+ - deserialization
40
+ - cwe-502
41
+ - owasp-a08
42
+
43
+ examples:
44
+ bad: |
45
+ obj = pickle.loads(request_body)
46
+
47
+ good: |
48
+ obj = json.loads(request_body)
@@ -0,0 +1,51 @@
1
+ # Python Security
2
+ # Detects non-cryptographic randomness API usage in security-sensitive code paths.
3
+ id: python-insecure-random
4
+ name: Insecure Randomness
5
+ severity: warning
6
+ category: security
7
+ defect_class: injection
8
+ inline_tier: warning
9
+ language: python
10
+
11
+ message: "Insecure randomness source detected — use secrets or os.urandom for security-sensitive values"
12
+
13
+ description: |
14
+ random.* is deterministic and unsuitable for security-sensitive tokens or secrets.
15
+
16
+ ✅ FIX: use secrets.token_urlsafe, secrets.randbelow, or os.urandom.
17
+
18
+ query: |
19
+ (call
20
+ function: (attribute
21
+ object: (identifier) @MOD
22
+ attribute: (identifier) @FN)
23
+ arguments: (argument_list) @ARGS)
24
+ (#eq? @MOD "random")
25
+ (#match? @FN "^(random|randint|randrange|choice|choices)$")
26
+
27
+ metavars:
28
+ - MOD
29
+ - FN
30
+ - ARGS
31
+
32
+ cwe:
33
+ - CWE-330
34
+ owasp:
35
+ - A02
36
+ confidence: medium
37
+
38
+ has_fix: false
39
+
40
+ tags:
41
+ - python
42
+ - security
43
+ - randomness
44
+ - weak-prng
45
+
46
+ examples:
47
+ bad: |
48
+ token = random.randint(100000, 999999)
49
+
50
+ good: |
51
+ token = secrets.randbelow(900000) + 100000
@@ -0,0 +1,55 @@
1
+ # Python Security
2
+ # Detects file access APIs used with dynamic path expressions.
3
+ id: python-path-traversal
4
+ name: Path Traversal Risk
5
+ severity: warning
6
+ category: security
7
+ defect_class: injection
8
+ inline_tier: warning
9
+ language: python
10
+
11
+ message: "Potential path traversal sink — sanitize and constrain file paths"
12
+
13
+ description: |
14
+ File operations with user-controlled paths can access unintended files.
15
+
16
+ ✅ FIX: normalize paths and enforce a fixed base directory allowlist.
17
+
18
+ query: |
19
+ [
20
+ (call
21
+ function: (identifier) @FN
22
+ arguments: (argument_list
23
+ [(identifier) (binary_operator) (call)] @PATH))
24
+ (call
25
+ function: (attribute
26
+ object: (identifier) @MOD
27
+ attribute: (identifier) @FN)
28
+ arguments: (argument_list
29
+ [(identifier) (binary_operator) (call)] @PATH))
30
+ ]
31
+ (#match? @FN "^(open|read_text|read_bytes|write_text|write_bytes|remove|unlink|rmdir)$")
32
+
33
+ metavars:
34
+ - MOD
35
+ - FN
36
+ - PATH
37
+
38
+ post_filter: py_path_traversal_sink
39
+
40
+ has_fix: false
41
+
42
+ tags:
43
+ - python
44
+ - security
45
+ - path-traversal
46
+ - cwe-22
47
+ - owasp-a01
48
+
49
+ examples:
50
+ bad: |
51
+ open(base + user_path)
52
+
53
+ good: |
54
+ safe = os.path.normpath(user_path)
55
+ open(os.path.join(BASE_DIR, safe))
@@ -0,0 +1,47 @@
1
+ # Python Security
2
+ # Detects dynamic SQL passed into execute-like APIs.
3
+ id: python-sql-injection
4
+ name: SQL Injection Risk
5
+ severity: warning
6
+ category: security
7
+ defect_class: injection
8
+ inline_tier: warning
9
+ language: python
10
+
11
+ message: "Potential SQL injection sink — use parameterized queries"
12
+
13
+ description: |
14
+ Dynamic SQL strings passed to execute-style APIs can enable SQL injection.
15
+
16
+ ✅ FIX: use placeholders and parameter binding instead of string composition.
17
+
18
+ query: |
19
+ (call
20
+ function: (attribute
21
+ attribute: (identifier) @FN)
22
+ arguments: (argument_list
23
+ [(binary_operator) (identifier) (call)] @SQL
24
+ (_)*))
25
+ (#match? @FN "^(execute|executemany|query|raw)$")
26
+
27
+ metavars:
28
+ - FN
29
+ - SQL
30
+
31
+ post_filter: py_sql_injection_sink
32
+
33
+ has_fix: false
34
+
35
+ tags:
36
+ - python
37
+ - security
38
+ - sql-injection
39
+ - cwe-89
40
+ - owasp-a03
41
+
42
+ examples:
43
+ bad: |
44
+ cursor.execute("SELECT * FROM users WHERE id = " + user_id)
45
+
46
+ good: |
47
+ cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
@@ -0,0 +1,50 @@
1
+ # Python Security
2
+ # Detects user-controlled URL usage in outbound HTTP request sinks.
3
+ id: python-ssrf
4
+ name: SSRF Risk
5
+ severity: warning
6
+ category: security
7
+ defect_class: injection
8
+ inline_tier: warning
9
+ language: python
10
+
11
+ message: "Potential SSRF sink — validate/allowlist outbound URLs"
12
+
13
+ description: |
14
+ Outbound HTTP calls with untrusted URLs can allow server-side request forgery.
15
+
16
+ ✅ FIX: enforce allowlisted hosts/schemes and reject private/internal targets.
17
+
18
+ query: |
19
+ (call
20
+ function: (attribute
21
+ object: (identifier) @MOD
22
+ attribute: (identifier) @FN)
23
+ arguments: (argument_list
24
+ [(identifier) (subscript) (call)] @URL))
25
+ (#eq? @MOD "requests")
26
+ (#match? @FN "^(get|post|put|patch|delete|request|head|options)$")
27
+
28
+ metavars:
29
+ - MOD
30
+ - FN
31
+ - URL
32
+
33
+ post_filter: py_ssrf_sink
34
+
35
+ has_fix: false
36
+
37
+ tags:
38
+ - python
39
+ - security
40
+ - ssrf
41
+ - cwe-918
42
+ - owasp-a10
43
+
44
+ examples:
45
+ bad: |
46
+ requests.get(user_url)
47
+
48
+ good: |
49
+ if host in ALLOWLIST:
50
+ requests.get(url)
@@ -0,0 +1,58 @@
1
+ # Python Concurrency
2
+ # Detects thread creation sites where shared state safety should be reviewed.
3
+ id: python-thread-global-write
4
+ name: Threaded Shared State Risk
5
+ severity: warning
6
+ category: concurrency
7
+ defect_class: async-misuse
8
+ inline_tier: warning
9
+ language: python
10
+
11
+ message: "Thread creation detected — ensure shared state mutations are synchronized"
12
+
13
+ description: |
14
+ Creating threads in code paths that touch shared mutable state can introduce races.
15
+
16
+ ✅ FIX: guard shared state with Lock/RLock or redesign ownership boundaries.
17
+
18
+ query: |
19
+ (call
20
+ function: (attribute
21
+ object: (identifier) @MOD
22
+ attribute: (identifier) @FN)
23
+ arguments: (argument_list) @ARGS)
24
+ (#eq? @MOD "threading")
25
+ (#eq? @FN "Thread")
26
+
27
+ metavars:
28
+ - MOD
29
+ - FN
30
+ - ARGS
31
+
32
+ cwe:
33
+ - CWE-362
34
+ owasp:
35
+ - A09
36
+ confidence: medium
37
+
38
+ has_fix: false
39
+
40
+ tags:
41
+ - python
42
+ - concurrency
43
+ - shared-state
44
+ - threading
45
+
46
+ examples:
47
+ bad: |
48
+ counter = 0
49
+ def worker():
50
+ global counter
51
+ counter += 1
52
+ threading.Thread(target=worker).start()
53
+
54
+ good: |
55
+ lock = threading.Lock()
56
+ def worker():
57
+ with lock:
58
+ update_state()