Browse Source

Update documentation and make rc more readable

pull/646/head
Augusto 4 years ago committed by xpetit
parent
commit
f26ca55c9f
  1. 187
      go/tests/rc/README.md
  2. 119
      go/tests/rc/rc.go

187
go/tests/rc/README.md

@ -1,131 +1,130 @@
## rc (restrictions checker)
### RC (Restrictions Checker)
This program analyses a go source file and displays in standard output the imports, functions, array types and loops used without authorization.
This program analyzes a go source file and displays in standard output the imports, functions, slice types and loops used without authorization.
### By default:
- NO imports and NO built-in functions are allowed.
- NO casting is allowed either.
- Only functions declared inside the source file are allowed.
- All array types are allowed
- Loops are allowed
- Allowed
- All functions declared inside the source file are allowed
- Slices of all types are allowed
- Loops are allowed
- Relative imports are allowed
- Disallowed
- NO imports are allowed
- NO built-in functions are allowed.
- NO casting is allowed
### Flags
- Two flags are defined:
- `--cast` allows casting to every built-in type.
- `--no-for` prohibits the use of `for` loops in the program or function.
- `--no-array`:
- Prohibits all array types if no types are specified after the flag.
Ex.
```console
_$ ./rc main.go fmt.* github.com/01-edu/z01.PrintRune len --no-array
```
All array type in main.go will cause an error message.
- Prohibits only the types specified after the flag
Ex.
```console
_$ ./rc main.go fmt.* github.com/01-edu/z01.PrintRune len --no-array rune string
```
Only array from the type rune and string are prohibit. All other array from built-in types are allowed
- `-h` for help
- `-cast` allows casting to every built-in type.
- `-no-for` prohibits the use of `for` loops in the program or function.
- `-allow-builtin` allows all builtin functions and casting to builtin types
- `-no-slices` disallows the use of all slices types
- `-no-these-slices=type1,type2`: disallows the slices of type1 and type2
- `-no-relative-imports`: disallows the use of relative imports
- `--no-lit="{PATTERN}"`: disallows character and string literals that match the pattern `PATTERN` which represent a Regular Expression
### Arguments:
- First Argument:
The program must be executed passing the go source file to be analyze as the first argument
- The remaining argument (from 2 to ...):
Can be (without any particular order):
- Flags can be passed at any point (in the begginig, middle or end) of the argument list
- The remaining arguments represent the allowed functions
- Allowed imports and functions from a package
- `<package>.*` for full imports (all functions from that package are allowed)
- `<package>`.`<function>` for partial imports (only the function is allowed)
- `<package>`.`<function>#amout` for certain amounts (only certain amount os a function is allowed)
- Ex: `fmt.*` (all functions from `fmt` are allowed), `github.com/01-edu/z01.PrintRune` (only `z01.PrintRune` is allowed), `append#2` (the only amount of `append`'s allowed is 2)
- `<package>`.`<function>#amount` the function is only allowed to be used `amount` number of times
- Ex: `fmt.*` (all functions from `fmt` are allowed), `github.com/01-edu/z01.PrintRune` (only `z01.PrintRune` is allowed), `fmt.Println#2` (fmt.Println can only be used 2 times or less)
- Allowed built-in functions
- Use the name of the built-in function
- Ex: `make`, `append`, `len`.
- Allowed casting
- by using the type of casting, ex: for allowing `string` casting, use `string`
- Or use the flag `--cast`, to allow every type of casting
- It is posible to limit the number of calls of a functions like with the imports using the '#' character
- Ex: `make`, `append`, `len`, `print#2`.
- Import relative packages
### Example:
- Use the relative path
- Ex: `../piscine`, `..`, `.`
- To allow the import of the whole `fmt` package, `z01.PrintRune` and the built-in functions `len` for the file `main.go`
Note: The imports must be writen exactly the way they are writen inside the source code, example:
- Unallow for loops
- Use the flags `--no-for`.
- Note: remember to use it before the `--no-array` flag.
- ex:
```console
_$ ./rc main.go fmt.* github.com/01-edu/z01.PrintRune len --no-array <...> --no-for
```
the last line produces undesired behaviors.
- Unallow literals
- Use the flag `--no-lit="{PATTERN}"`
- Note: `"{PATTERN}"` must be a valid RegExp.
- ex:
```console
_$ ./rc main.go fmt.* github.com/01-edu/z01.PrintRune len --no-array --no-lit=[b-yB-Y]
```
```console
_$ rc main.go fmt.* github.com/01-edu/z01.PrintRune len
```
- Optional lasts arguments
- The flag `--no-array` must be given as the last argument or to signal that all the arguments after are unallowed array types
- Import "fmt" is allowed by executing
```console
_$ rc sourcefile.go fmt.*
```
### Usage:
- Import "go/parser" is allowed by executing
```console
_$ rc sourcefile.go go/parser.*
```
- To allow the import of the whole `fmt` package, `z01.PrintRune` and the built-in functions len in the file `main.go`
- Import "github.com/01-edu/z01" is allowed by executing
```console
_$ rc sourcefile.go github.com/01-edu/z01.*
```
The imports must be writen exactly the way are writen inside the source code, example:
- Disallow literals
- Use the flag `--no-lit="{PATTERN}"`
```console
_$ rc -no-slices --no-lit=[b-yB-Y] main.go fmt.* github.com/01-edu/z01.PrintRune len
```
```console
_$ ./rc main.go fmt.* github.com/01-edu/z01.PrintRune len
```
- Allow all type of casting
- More examples:
```console
_$ rc -cast sourcefile.go fmt.* github.com/01-edu/z01 os.* strconv.* make len append
```
- this will allow all type of casting in the file sourcefile.go
- import "fmt" is allowed by executing
- Disallow the use of the slices of type `string` and `int`
```console
_$ ./rc sourcefile.go fmt.*
```
```console
_$ rc -no-these-slices=string,int sourcefile.go
```
- import "go/parser" is allowed by executing
- To allow just one type of casting
```console
_$ ./rc sourcefile.go go/parser.*
```
```console
_$ rc sourcefile.go fmt.* github.com/01-edu/z01 os.* strconv.* make len append rune
```
- this will allow the casting to `rune`, but not `int8`, ..., `string`, `float32`, ...
- import "github.com/01-edu/z01" is allowed by executing
### How to read the error message
```console
./rc sourcefile.go github.com/01-edu/z01.*
```
Let us look to an example snipped of code, let us imagine this code in a file called `main.go`:
- import "../../../all/tests/go/solutions" is allowed by executing
```go
package main
```console
_$ ./rc sourcefile.go ../../../all/tests/go/solutions
```
import "fmt"
(no `.*` is needed, all the functions from this relative package are allowed)
- allow all type of casting
```console
_$ ./rc sourcefile.go ../../../all/tests/go/solutions/ztail/ztail.go fmt.* github.com/01-edu/z01 os.* strconv.* make len append --cast
```
- this will allow all type of casting in the file ztail.go
func main() {
for _, v := range "abcdefghijklmnopqrstuvwxyz" {
fmt.Println(v)
}
fmt.Println()
}
```
- to allow just one type of casting
Now let us run the `rc` and understand the message
```console
_$ ./rc sourcefile.go ../../../all/tests/go/solutions/ztail/ztail.go fmt.* github.com/01-edu/z01 os.* strconv.* make len append rune
```
```console
_$ rc main.go github.com/01-edu/z01.PrintRune
Parsing:
Ok
Cheating:
TYPE: NAME: LOCATION:
illegal-import fmt main.go:3:8
illegal-access fmt.Println main.go:7:3
illegal-access fmt.Println main.go:10:2
illegal-definition main main.go:5:1
```
- this will allow `rune`, but not `int8`, ..., `string`, `float32`, ...
The important part is printed after the `Cheating` tag:
- The import of of the package `fmt` is not allowed
- In go the dot (.) is also known as the access operator for that reason the use of fmt.Println is shown as an illegal-access
- Finally the main function is shown as illegal-definition because the function is using disallowed functions that does not mean that the function can not be defined it just mean that the definition of the function must be changed to not use disallowed functions.
- Notice that the third column of the output with the tag "LOCATION:" show the location in the following way filepath:line:column
This mean that you have to substitute the illegal function for ones that are allowed or write your own function with allowed functions

119
go/tests/rc/rc.go

@ -415,6 +415,7 @@ func (info *info) add(v *visitor) {
// Returns the info structure with all the ocurrences of the element
// of the analised in the project
// TODO: Refactor so this function has only one responsibility
func isAllowed(function *element, path string, load loadedSource, walked map[ast.Node]bool, info *info) bool {
functionObj := lookupDefinitionObj(function, path, load)
definedLocally := functionObj != nil
@ -561,8 +562,78 @@ func analyzeProgram(filename, path string, load loadedSource) *info {
return info
}
func parseArgs(toAllow []string, builtins bool, casting bool) error {
allowedFun["builtin"] = make(map[string]bool)
func parseArgs(toAllow []string) error {
allowBuiltins()
allowCasting()
for _, v := range toAllow {
err := allowFunction(v)
if err != nil {
return err
}
}
return nil
}
func allowFunction(functionPath string) error {
functionName := functionName(functionPath)
packageName := packageName(functionPath)
// for github.com/01-edu/z01 shortName = z01
packageShortName := filepath.Base(packageName)
restrictsRepetitions := strings.ContainsRune(functionPath, '#')
if restrictsRepetitions {
allowedReps, err := repetitionsAllowed(functionPath)
if err != nil {
return err
}
allowedRep[packageShortName+"."+functionName] = allowedReps
}
if allowedFun[packageName] == nil {
allowedFun[packageName] = make(map[string]bool)
}
allowedFun[packageName][functionName] = true
return nil
}
func functionName(functionPath string) string {
segmentedPath := strings.Split(functionPath, ".")
return segmentedPath[len(segmentedPath)-1]
}
func packageName(functionPath string) string {
segmentedPath := strings.Split(functionPath, ".")
hasNoPackage := len(segmentedPath) < 2
if hasNoPackage {
return "builtin"
}
return strings.Join(segmentedPath[:len(segmentedPath)-1], ".")
}
// Assumes that `functionPath` contains `#`
func repetitionsAllowed(functionPath string) (int, error) {
segmentedPath := strings.Split(functionPath, "#")
repetitions := segmentedPath[len(segmentedPath)-1]
allowedReps, err := strconv.Atoi(repetitions)
if err != nil {
return allowedReps, fmt.Errorf("After the '#' there should be an integer" +
" representing the maximum number of allowed occurrences")
}
return allowedReps, nil
}
func allowBuiltins() {
if allowedFun["builtin"] == nil {
allowedFun["builtin"] = make(map[string]bool)
}
if allowBuiltin {
allowedFun["builtin"]["*"] = true
}
}
func allowCasting() {
if allowedFun["builtin"] == nil {
allowedFun["builtin"] = make(map[string]bool)
}
predeclaredTypes := []string{"bool", "byte", "complex64", "complex128",
"error", "float32", "float64", "int", "int8",
"int16", "int32", "int64", "rune", "string",
@ -570,55 +641,11 @@ func parseArgs(toAllow []string, builtins bool, casting bool) error {
"uintptr",
}
if builtins {
allowedFun["builtin"]["*"] = true
}
if casting {
for _, v := range predeclaredTypes {
allowedFun["builtin"][v] = true
}
}
for _, v := range toAllow {
var path, funcName string
if strings.ContainsRune(v, '/') {
path = filepath.Dir(v)
funcName = filepath.Base(v)
spl := strings.Split(funcName, ".")
path = path + "/" + spl[0]
if len(spl) > 1 {
funcName = spl[1]
}
} else if strings.ContainsRune(v, '.') {
spl := strings.Split(v, ".")
path = spl[0]
if len(spl) > 1 {
funcName = spl[1]
}
} else {
path = "builtin"
funcName = v
}
if strings.ContainsRune(funcName, '#') {
spl := strings.Split(funcName, "#")
funcName = spl[0]
n, err := strconv.Atoi(spl[1])
if err != nil {
return fmt.Errorf("After the '#' there should be an integer" +
" representing the maximum number of allowed occurrences")
}
var prefix string
if path != "" {
prefix = filepath.Base(path)
}
allowedRep[prefix+"."+funcName] = n
}
if allowedFun[path] == nil {
allowedFun[path] = make(map[string]bool)
}
allowedFun[path][funcName] = true
}
return nil
}
func printIllegals(illegals []*illegal) {

Loading…
Cancel
Save