From 9195787f8bd613c8d8c6a79f6dc904b9c9584d9d Mon Sep 17 00:00:00 2001 From: Adam Mohammed Date: Thu, 13 Jul 2023 10:33:43 -0400 Subject: [PATCH] doit --- static-analysis/.envrc | 3 + static-analysis/.gitignore | 5 + static-analysis/01_simple_add.rb | 4 + static-analysis/02_syntax_vs_semantics.rb | 1 + static-analysis/03_scoping.rb | 6 + static-analysis/04_vrfs_params.rb | 9 ++ static-analysis/Gemfile | 5 + static-analysis/Gemfile.lock | 42 ++++++ static-analysis/README.org | 101 ++++++++++++++ static-analysis/create_params.rb | 57 ++++++++ static-analysis/devenv.lock | 156 ++++++++++++++++++++++ static-analysis/devenv.nix | 29 ++++ static-analysis/devenv.yaml | 3 + static-analysis/hash_key_example.rb | 2 + static-analysis/rubocop | 1 + static-analysis/test1.rb | 3 + 16 files changed, 427 insertions(+) create mode 100644 static-analysis/.envrc create mode 100644 static-analysis/.gitignore create mode 100644 static-analysis/01_simple_add.rb create mode 100644 static-analysis/02_syntax_vs_semantics.rb create mode 100644 static-analysis/03_scoping.rb create mode 100644 static-analysis/04_vrfs_params.rb create mode 100644 static-analysis/Gemfile create mode 100644 static-analysis/Gemfile.lock create mode 100644 static-analysis/README.org create mode 100644 static-analysis/create_params.rb create mode 100644 static-analysis/devenv.lock create mode 100644 static-analysis/devenv.nix create mode 100644 static-analysis/devenv.yaml create mode 100644 static-analysis/hash_key_example.rb create mode 160000 static-analysis/rubocop create mode 100644 static-analysis/test1.rb diff --git a/static-analysis/.envrc b/static-analysis/.envrc new file mode 100644 index 0000000..6de8a8a --- /dev/null +++ b/static-analysis/.envrc @@ -0,0 +1,3 @@ +source_url "https://raw.githubusercontent.com/cachix/devenv/d1f7b48e35e6dee421cfd0f51481d17f77586997/direnvrc" "sha256-YBzqskFZxmNb3kYVoKD9ZixoPXJh1C9ZvTLGFRkauZ0=" + +use devenv \ No newline at end of file diff --git a/static-analysis/.gitignore b/static-analysis/.gitignore new file mode 100644 index 0000000..715bef4 --- /dev/null +++ b/static-analysis/.gitignore @@ -0,0 +1,5 @@ + +# Devenv +.devenv* +devenv.local.nix + diff --git a/static-analysis/01_simple_add.rb b/static-analysis/01_simple_add.rb new file mode 100644 index 0000000..9b2a93d --- /dev/null +++ b/static-analysis/01_simple_add.rb @@ -0,0 +1,4 @@ +x = 1 +y = 2 +z = x + y +puts z diff --git a/static-analysis/02_syntax_vs_semantics.rb b/static-analysis/02_syntax_vs_semantics.rb new file mode 100644 index 0000000..92dadfb --- /dev/null +++ b/static-analysis/02_syntax_vs_semantics.rb @@ -0,0 +1 @@ +x = 5 + "rocks" diff --git a/static-analysis/03_scoping.rb b/static-analysis/03_scoping.rb new file mode 100644 index 0000000..2530e66 --- /dev/null +++ b/static-analysis/03_scoping.rb @@ -0,0 +1,6 @@ +x = 1 +begin + x = 3 +end +->(x) { x + 1 } +puts x diff --git a/static-analysis/04_vrfs_params.rb b/static-analysis/04_vrfs_params.rb new file mode 100644 index 0000000..fca5bef --- /dev/null +++ b/static-analysis/04_vrfs_params.rb @@ -0,0 +1,9 @@ +params.permit([1, 2, 3]) + +params2 + .permit(["a", "b", "c"]) + + +params3 + . + permit(["x", "y", "z"]) diff --git a/static-analysis/Gemfile b/static-analysis/Gemfile new file mode 100644 index 0000000..78a757b --- /dev/null +++ b/static-analysis/Gemfile @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'rubocop', path: '/home/adammo/repos/presentations/static-analysis/rubocop' diff --git a/static-analysis/Gemfile.lock b/static-analysis/Gemfile.lock new file mode 100644 index 0000000..836b12f --- /dev/null +++ b/static-analysis/Gemfile.lock @@ -0,0 +1,42 @@ +PATH + remote: rubocop + specs: + rubocop (1.54.1) + json (~> 2.3) + language_server-protocol (>= 3.17.0) + parallel (~> 1.10) + parser (>= 3.2.2.3) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.28.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 3.0) + +GEM + remote: https://rubygems.org/ + specs: + ast (2.4.2) + json (2.6.3) + language_server-protocol (3.17.0.3) + parallel (1.23.0) + parser (3.2.2.3) + ast (~> 2.4.1) + racc + racc (1.7.1) + rainbow (3.1.1) + regexp_parser (2.8.1) + rexml (3.2.5) + rubocop-ast (1.29.0) + parser (>= 3.2.1.0) + ruby-progressbar (1.13.0) + unicode-display_width (2.4.2) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + rubocop! + +BUNDLED WITH + 2.2.33 diff --git a/static-analysis/README.org b/static-analysis/README.org new file mode 100644 index 0000000..9588aa9 --- /dev/null +++ b/static-analysis/README.org @@ -0,0 +1,101 @@ +#+TITLE: Program Analysis +#+Author: Adam Mohammed + + +* Program Analysis tools + +Generally program analysis tools come in two forms, static and +dynamic. Each has tradeoffs that we need to understand, especially +when we start to build these tools. + +It's important to understand what each analysis tool is good for, +knowing what it's strong at detecting, as well as knowing what they +are not good for and where they struggle. + +** Examples of Static Analysis +RuboCop +Gofmt +Rufo +*** Good +- Detecting syntax errors +- Detecting simple semantic errors +- Detecting style violations +- Detecting code convention violations + +*** Bad +- Prone to false positives and false negatives +- Requires access to source code, including libraries +- Does not account for runtime environment + + +** Examples of Dynamic Analysis +Profilers +- ruby-prof + +Memory leak detection +- Valgrind + +Data Races +- Go race detector + + + + +*** Good +- Detect bugs that only can occur at runtime +- Capable of measuring things inlfuenced by factors outside of source code + - e.g. Network latency, External errors, etc +- Generally less false positives and false negatives because error + cases must occur to be detected + +*** Bad +- Requires actually violating edge cases to report them +- Often incurs performance penalty to instrument live code +- True positives can be missed for code paths that are not exercised often. + + +** Problem we're actually facing + +- Monolith is large and old +- OAS is used as the source of truth to generate clients and documentation that customers rely on +- Monolith and OAS don't agree most of the time + + +** Solutions we're trying + +https://github.com/equinixmetal/api-spec-inspector - form of SA + + +** Back to basics + +How do programming languages do their job? + +Source code -> interpreted -> output + +If you're in a compiled languages + +source code -> compiled -> executable -> output + + +We treat "interpreters" and "compilers" as black boxes for the most part. + +Let's pull back the curtains on these things though: + +** How does code get interpreted? + +1. Show ruby-parse + +2. Talk about AST + +** Utilizing the AST + +ex 01-03_ + +** Problem areas for test parsing + +ex 04 vrf params + + +** Rubocop Examples + +https://github.com/rubocop/rubocop/blob/02c32b4cf3801f9cf4cca4b3f1f4288aaee2ad5c/lib/rubocop/cop/lint/useless_setter_call.rb diff --git a/static-analysis/create_params.rb b/static-analysis/create_params.rb new file mode 100644 index 0000000..35ff3e4 --- /dev/null +++ b/static-analysis/create_params.rb @@ -0,0 +1,57 @@ +def create + @interconnection = if create_with_service_tokens? + ::Network::Interconnection::Connection::CreateWithServiceTokens.call(create_with_service_tokens_params) + else + ::Network::Interconnection::Connection::Create.call(create_params) + end + + if @interconnection.valid? + render "interconnections/connections/show", status: :created, location: interconnection_path(@interconnection.id) + else + render_validation_errors(@interconnection) + end +end + +def create_params + # TODO: Remove facility from create params after making metro required in swagger docs + @facility = Facility.find_by_id_or(:code, params[:facility_id]) if params[:facility_id] + params.required([:name, :redundancy, :type]) + params[:contact_email] = current_user.email unless params.has_key?(:contact_email) + params[:speed] = ::Network::Interconnection::InterconnectionPort.parse_speed(params[:speed]) if params.has_key?(:speed) + permitted = [:contact_email, :description, :name, :redundancy, :speed, :facility_id, :metro_id, :metro, :type, tags: []] + + permitted << { vlans: [] } if advanced_shared_create_enabled? + permitted << :mode if dedicated_interconnection_mode_enabled? && params[:type] == "dedicated" + + params + .permit(*permitted) + .merge( + facility: @facility, + metro: @metro, + project: @project, + organization: @organization, + virtual_networks: @virtual_networks, + ) +end + + +def create_with_service_tokens_params + set_service_token_params + + # TODO: Remove VRF feature flag check after VRF is released. + array_params = { tags: [], vlans: [] } + array_params = array_params.merge(vrfs: []) if Feature.enabled?(Feature::VRF_ON_SHARED_CONNECTIONS, @organization) + + permitted = [:description, :locked, :name, :redundancy, :speed, :contact_email, :metro_id, :type, :service_token_type, array_params] + normalize_params + + params + .permit(*permitted) + .merge( + vrfs: @vrfs, + metro: @metro, + project: @project, + organization: @organization, + virtual_networks: @virtual_networks, + ) +end diff --git a/static-analysis/devenv.lock b/static-analysis/devenv.lock new file mode 100644 index 0000000..bac3244 --- /dev/null +++ b/static-analysis/devenv.lock @@ -0,0 +1,156 @@ +{ + "nodes": { + "devenv": { + "locked": { + "dir": "src/modules", + "lastModified": 1689195827, + "narHash": "sha256-0+vH0tLjScnR6mpywjIOqS9BGbBUWY8IcWXuo/j6+l8=", + "owner": "cachix", + "repo": "devenv", + "rev": "7d5b629ec05db9b954a1cfc34a0fafec420e7377", + "type": "github" + }, + "original": { + "dir": "src/modules", + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1685518550, + "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1660459072, + "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1689168768, + "narHash": "sha256-mCw3LPg2jJkapvJpkd1IZ8k0IJlSG2ECvz3vcOAu+Uo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "6fd9edc94426a3c050ad589c8f033b5ca55454c7", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1685801374, + "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c37ca420157f4abc31e26f436c1145f8951ff373", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1688596063, + "narHash": "sha256-9t7RxBiKWHygsqXtiNATTJt4lim/oSYZV3RG8OjDDng=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "c8d18ba345730019c3faf412c96a045ade171895", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "devenv": "devenv", + "nixpkgs": "nixpkgs", + "pre-commit-hooks": "pre-commit-hooks" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/static-analysis/devenv.nix b/static-analysis/devenv.nix new file mode 100644 index 0000000..0990800 --- /dev/null +++ b/static-analysis/devenv.nix @@ -0,0 +1,29 @@ +{ pkgs, ... }: + +{ + + # https://devenv.sh/packages/ + packages = [ + pkgs.ruby_3_0 + pkgs.rubyPackages_3_0.rubocop + ]; + + # https://devenv.sh/scripts/ + scripts.hello.exec = "echo hello from $GREET"; + + enterShell = '' + hello + git --version + ''; + + # https://devenv.sh/languages/ + # languages.nix.enable = true; + + # https://devenv.sh/pre-commit-hooks/ + # pre-commit.hooks.shellcheck.enable = true; + + # https://devenv.sh/processes/ + # processes.ping.exec = "ping example.com"; + + # See full reference at https://devenv.sh/reference/options/ +} diff --git a/static-analysis/devenv.yaml b/static-analysis/devenv.yaml new file mode 100644 index 0000000..c7cb5ce --- /dev/null +++ b/static-analysis/devenv.yaml @@ -0,0 +1,3 @@ +inputs: + nixpkgs: + url: github:NixOS/nixpkgs/nixpkgs-unstable diff --git a/static-analysis/hash_key_example.rb b/static-analysis/hash_key_example.rb new file mode 100644 index 0000000..0e99c7b --- /dev/null +++ b/static-analysis/hash_key_example.rb @@ -0,0 +1,2 @@ +k = {a: 1, b: 2, a: 3} +puts k diff --git a/static-analysis/rubocop b/static-analysis/rubocop new file mode 160000 index 0000000..02c32b4 --- /dev/null +++ b/static-analysis/rubocop @@ -0,0 +1 @@ +Subproject commit 02c32b4cf3801f9cf4cca4b3f1f4288aaee2ad5c diff --git a/static-analysis/test1.rb b/static-analysis/test1.rb new file mode 100644 index 0000000..306b0a6 --- /dev/null +++ b/static-analysis/test1.rb @@ -0,0 +1,3 @@ +x = 1 +y = 2 +x + y